Devel
Threads by month
- ----- 2026 -----
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 51 participants
- 40078 discussions
virCommandProcessIO: It's reading from stdout or stderr of child,
but not reading.
---
src/util/command.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/src/util/command.c b/src/util/command.c
index cb682fc..81a2345 100644
--- a/src/util/command.c
+++ b/src/util/command.c
@@ -1504,7 +1504,9 @@ virCommandProcessIO(virCommandPtr cmd)
if (errno != EINTR &&
errno != EAGAIN) {
virReportSystemError(errno, "%s",
- _("unable to write to child input"));
+ (fds[i].fd == outfd) ?
+ _("unable to read child stdout") :
+ _("unable to read child stderr"));
goto cleanup;
}
} else if (done == 0) {
--
1.7.4
2
2
* src/qemu/qemu_domain.c: (qemuDomainAppendLog)
Free "message" in "cleanup".
---
src/qemu/qemu_domain.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 5fe66ac..fab316f 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -947,5 +947,6 @@ cleanup:
if (fd != logFD)
VIR_FORCE_CLOSE(fd);
+ VIR_FREE(message);
return ret;
}
--
1.7.4
2
2
22 Jun '11
In a first cleanup step, make nlComm from macvtap.c commonly available
for other code to use. Since nlComm uses Linux-specific structures as
parameters it's prototype is only visible on Linux.
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/Makefile.am | 1
src/libvirt_private.syms | 4 +
src/util/macvtap.c | 98 ----------------------------------
src/util/netlink.c | 135
+++++++++++++++++++++++++++++++++++++++++++++++
src/util/netlink.h | 14 ++++
5 files changed, 155 insertions(+), 97 deletions(-)
Index: libvirt-acl/src/Makefile.am
===================================================================
--- libvirt-acl.orig/src/Makefile.am
+++ libvirt-acl/src/Makefile.am
@@ -63,6 +63,7 @@ UTIL_SOURCES = \
util/logging.c util/logging.h \
util/macvtap.c util/macvtap.h \
util/memory.c util/memory.h \
+ util/netlink.c util/netlink.h \
util/pci.c util/pci.h \
util/processinfo.c util/processinfo.h \
util/hostusb.c util/hostusb.h \
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -39,12 +39,8 @@
# include <sys/ioctl.h>
# include <linux/if.h>
-# include <linux/netlink.h>
-# include <linux/rtnetlink.h>
# include <linux/if_tun.h>
-# include <netlink/msg.h>
-
/* Older kernels lacked this enum value. */
# if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
# define MACVLAN_MODE_PASSTHRU 8
@@ -64,6 +60,7 @@
# include "virterror_internal.h"
# include "uuid.h"
# include "files.h"
+# include "netlink.h"
# define VIR_FROM_THIS VIR_FROM_NET
@@ -79,8 +76,6 @@
# define NLMSGBUF_SIZE 256
# define RATTBUF_SIZE 64
-# define NETLINK_ACK_TIMEOUT_S 2
-
# define STATUS_POLL_TIMEOUT_USEC (10 * MICROSEC_PER_SEC)
# define STATUS_POLL_INTERVL_USEC (MICROSEC_PER_SEC / 8)
@@ -96,97 +91,6 @@ enum virVirtualPortOp {
};
-/**
- * nlComm:
- * @nlmsg: pointer to netlink message
- * @respbuf: pointer to pointer where response buffer will be allocated
- * @respbuflen: pointer to integer holding the size of the response buffer
- * on return of the function.
- * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel
- *
- * Send the given message to the netlink layer and receive response.
- * Returns 0 on success, -1 on error. In case of error, no response
- * buffer will be returned.
- */
-static
-int nlComm(struct nl_msg *nl_msg,
- unsigned char **respbuf, unsigned int *respbuflen,
- int nl_pid)
-{
- int rc = 0;
- struct sockaddr_nl nladdr = {
- .nl_family = AF_NETLINK,
- .nl_pid = nl_pid,
- .nl_groups = 0,
- };
- ssize_t nbytes;
- struct timeval tv = {
- .tv_sec = NETLINK_ACK_TIMEOUT_S,
- };
- fd_set readfds;
- int fd;
- int n;
- struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
- struct nl_handle *nlhandle = nl_handle_alloc();
-
- if (!nlhandle) {
- virReportSystemError(errno,
- "%s", _("cannot allocate nlhandle for
netlink"));
- return -1;
- }
-
- if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
- virReportSystemError(errno,
- "%s", _("cannot connect to netlink socket"));
- rc = -1;
- goto err_exit;
- }
-
- nlmsg_set_dst(nl_msg, &nladdr);
-
- nlmsg->nlmsg_pid = getpid();
-
- nbytes = nl_send_auto_complete(nlhandle, nl_msg);
- if (nbytes < 0) {
- virReportSystemError(errno,
- "%s", _("cannot send to netlink socket"));
- rc = -1;
- goto err_exit;
- }
-
- fd = nl_socket_get_fd(nlhandle);
-
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
-
- n = select(fd + 1, &readfds, NULL, NULL, &tv);
- if (n <= 0) {
- if (n < 0)
- virReportSystemError(errno, "%s",
- _("error in select call"));
- if (n == 0)
- virReportSystemError(ETIMEDOUT, "%s",
- _("no valid netlink response was
received"));
- rc = -1;
- goto err_exit;
- }
-
- *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
- if (*respbuflen <= 0) {
- virReportSystemError(errno,
- "%s", _("nl_recv failed"));
- rc = -1;
- }
-err_exit:
- if (rc == -1) {
- VIR_FREE(*respbuf);
- *respbuf = NULL;
- *respbuflen = 0;
- }
-
- nl_handle_destroy(nlhandle);
- return rc;
-}
# if WITH_MACVTAP
Index: libvirt-acl/src/util/netlink.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/util/netlink.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * 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
+ *
+ * Authors:
+ * Stefan Berger <stefanb(a)us.ibm.com>
+ *
+ * Notes:
+ * netlink: http://lovezutto.googlepages.com/netlink.pdf
+ * iproute2 package
+ *
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "netlink.h"
+#include "memory.h"
+#include "virterror_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_NET
+
+#define NETLINK_ACK_TIMEOUT_S 2
+
+/**
+ * nlComm:
+ * @nlmsg: pointer to netlink message
+ * @respbuf: pointer to pointer where response buffer will be allocated
+ * @respbuflen: pointer to integer holding the size of the response buffer
+ * on return of the function.
+ * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel
+ *
+ * Send the given message to the netlink layer and receive response.
+ * Returns 0 on success, -1 on error. In case of error, no response
+ * buffer will be returned.
+ */
+#if __linux__
+int nlComm(struct nl_msg *nl_msg,
+ unsigned char **respbuf, unsigned int *respbuflen,
+ int nl_pid)
+{
+ int rc = 0;
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK,
+ .nl_pid = nl_pid,
+ .nl_groups = 0,
+ };
+ ssize_t nbytes;
+ struct timeval tv = {
+ .tv_sec = NETLINK_ACK_TIMEOUT_S,
+ };
+ fd_set readfds;
+ int fd;
+ int n;
+ struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
+ struct nl_handle *nlhandle = nl_handle_alloc();
+
+ if (!nlhandle) {
+ virReportSystemError(errno,
+ "%s", _("cannot allocate nlhandle for
netlink"));
+ return -1;
+ }
+
+ if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
+ virReportSystemError(errno,
+ "%s", _("cannot connect to netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ nlmsg_set_dst(nl_msg, &nladdr);
+
+ nlmsg->nlmsg_pid = getpid();
+
+ nbytes = nl_send_auto_complete(nlhandle, nl_msg);
+ if (nbytes < 0) {
+ virReportSystemError(errno,
+ "%s", _("cannot send to netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ fd = nl_socket_get_fd(nlhandle);
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ n = select(fd + 1, &readfds, NULL, NULL, &tv);
+ if (n <= 0) {
+ if (n < 0)
+ virReportSystemError(errno, "%s",
+ _("error in select call"));
+ if (n == 0)
+ virReportSystemError(ETIMEDOUT, "%s",
+ _("no valid netlink response was
received"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
+ if (*respbuflen <= 0) {
+ virReportSystemError(errno,
+ "%s", _("nl_recv failed"));
+ rc = -1;
+ }
+err_exit:
+ if (rc == -1) {
+ VIR_FREE(*respbuf);
+ *respbuf = NULL;
+ *respbuflen = 0;
+ }
+
+ nl_handle_destroy(nlhandle);
+ return rc;
+}
+
+#endif /* __linux__ */
+
Index: libvirt-acl/src/util/netlink.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/util/netlink.h
@@ -0,0 +1,14 @@
+#ifndef __VIR_NETLINK_H__
+# define __VIR_NETLINK_H__
+
+# if __linux__
+
+# include <netlink/msg.h>
+
+int nlComm(struct nl_msg *nl_msg,
+ unsigned char **respbuf, unsigned int *respbuflen,
+ int nl_pid);
+
+#endif /* __linux__ */
+
+#endif /* __VIR_NETLINK_H__ */
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -668,6 +668,10 @@ virResizeN;
virShrinkN;
+#netlink.h
+nlComm;
+
+
# network.h
virSocketAddrBroadcast;
virSocketAddrBroadcastByPrefix;
3
3
Looking at
http://libvirt.org/html/libvirt-libvirt.html#virDomainShutoffReason as
an example, I see several places where there are spurious "*" in the
generated documentation. It looks like anywhere we have:
typedef enum {
VALUE = 0; /* Multi-line
* comment */
} virName;
that the python generator is not stripping out the '^ *\*?' regex for
continued comment lines.
My python is a bit too weak to quickly determine a fix, so I'm throwing
this out for anyone else who wants an easy bug to fix.
--
Eric Blake eblake(a)redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
2
5
22 Jun '11
For virtio disks and interfaces, qemu allows users to enable or disable
ioeventfd feature. This means, qemu can execute domain code, while
another thread waits for I/O event. Basically, in some cases it is win,
in some loss. This feature is available via 'ioeventfd' attribute in disk
and interface <driver> element. It accepts 'on' and 'off'. Leaving this
attribute out defaults to hypervisor decision.
---
diff to v1:
-reverted to 'ioeventfd' attribute:
https://www.redhat.com/archives/libvir-list/2011-June/msg00712.html
docs/formatdomain.html.in | 34 +++++++++++++-
docs/schemas/domain.rng | 14 ++++++
src/conf/domain_conf.c | 49 +++++++++++++++++++-
src/conf/domain_conf.h | 11 ++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 13 +++++
tests/qemuhelptest.c | 3 +-
.../qemuxml2argv-disk-ioeventfd.args | 11 ++++
.../qemuxml2argv-disk-ioeventfd.xml | 50 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 4 ++
12 files changed, 191 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index ab39417..39e1a85 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -785,7 +785,7 @@
</disk>
...
<disk type='network'>
- <driver name="qemu" type="raw" io="threads"/>
+ <driver name="qemu" type="raw" io="threads" ioeventfd="on"/>
<source protocol="sheepdog" name="image_name">
<host name="hostname" port="7000"/>
</source>
@@ -869,6 +869,20 @@
policies on I/O; qemu guests support "threads" and
"native". <span class="since">Since 0.8.8</span>
</li>
+ <li>
+ The optional <code>ioeventfd</code> attribute allows users to
+ set <a href='https://patchwork.kernel.org/patch/43390/'>
+ domain I/O asynchronous handling</a> for disk device.
+ The default is left to the discretion of the hypervisor.
+ Accepted values are "on" and "off". Enabling this allows
+ qemu to execute VM while a separate thread handles I/O.
+ Typically guests experiencing high system CPU utilization
+ during I/O will benefit from this. On the other hand,
+ on overloaded host it could increase guest I/O latency.
+ <span class="since">Since 0.9.3 (QEMU and KVM only)</span>
+ <b>In general you should leave this option alone, unless you
+ are very certain you know what you are doing.</b>
+ </li>
</ul>
</dd>
<dt><code>boot</code></dt>
@@ -1649,7 +1663,7 @@ qemu-kvm -net nic,model=? /dev/null
<source network='default'/>
<target dev='vnet1'/>
<model type='virtio'/>
- <b><driver name='vhost' txmode='iothread'/></b>
+ <b><driver name='vhost' txmode='iothread' ioeventfd='on'/></b>
</interface>
</devices>
...</pre>
@@ -1700,6 +1714,22 @@ qemu-kvm -net nic,model=? /dev/null
<b>In general you should leave this option alone, unless you
are very certain you know what you are doing.</b>
</dd>
+ <dt><code>ioeventfd</code></dt>
+ <dd>
+ This optional attribute allows users to set
+ <a href='https://patchwork.kernel.org/patch/43390/'>
+ domain I/O asynchronous handling</a> for interface device.
+ The default is left to the discretion of the hypervisor.
+ Accepted values are "on" and "off". Enabling this allows
+ qemu to execute VM while a separate thread handles I/O.
+ Typically guests experiencing high system CPU utilization
+ during I/O will benefit from this. On the other hand,
+ on overloaded host it could increase guest I/O latency.
+ <span class="since">Since 0.9.3 (QEMU and KVM only)</span><br/><br/>
+
+ <b>In general you should leave this option alone, unless you
+ are very certain you know what you are doing.</b>
+ </dd>
</dl>
<h5><a name="elementsNICSTargetOverride">Overriding the target element</a></h5>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 6de024e..891662d 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -778,6 +778,9 @@
<optional>
<ref name="driverIO"/>
</optional>
+ <optional>
+ <ref name="ioeventfd"/>
+ </optional>
<empty/>
</element>
</define>
@@ -817,6 +820,14 @@
</choice>
</attribute>
</define>
+ <define name="ioeventfd">
+ <attribute name="ioeventfd">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+ </define>
<define name="controller">
<element name="controller">
<choice>
@@ -1117,6 +1128,9 @@
</choice>
</attribute>
</optional>
+ <optional>
+ <ref name="ioeventfd"/>
+ </optional>
<empty/>
</element>
</optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5360863..2234857 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -163,6 +163,11 @@ VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
"default",
"native",
"threads")
+VIR_ENUM_IMPL(virDomainIoEventFd, VIR_DOMAIN_IO_EVENT_FD_LAST,
+ "default",
+ "on",
+ "off")
+
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"ide",
@@ -2013,6 +2018,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
char *cachetag = NULL;
char *error_policy = NULL;
char *iotag = NULL;
+ char *ioeventfd = NULL;
char *devaddr = NULL;
virStorageEncryptionPtr encryption = NULL;
char *serial = NULL;
@@ -2128,6 +2134,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
cachetag = virXMLPropString(cur, "cache");
error_policy = virXMLPropString(cur, "error_policy");
iotag = virXMLPropString(cur, "io");
+ ioeventfd = virXMLPropString(cur, "ioeventfd");
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -2264,6 +2271,24 @@ virDomainDiskDefParseXML(virCapsPtr caps,
}
}
+ if (ioeventfd) {
+ if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk ioeventfd mode supported "
+ "only for virtio bus"));
+ goto error;
+ }
+
+ int i;
+ if ((i = virDomainIoEventFdTypeFromString(ioeventfd)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown disk ioeventfd mode '%s'"),
+ ioeventfd);
+ goto error;
+ }
+ def->ioeventfd=i;
+ }
+
if (devaddr) {
if (virDomainParseLegacyDeviceAddress(devaddr,
&def->info.addr.pci) < 0) {
@@ -2326,6 +2351,7 @@ cleanup:
VIR_FREE(cachetag);
VIR_FREE(error_policy);
VIR_FREE(iotag);
+ VIR_FREE(ioeventfd);
VIR_FREE(devaddr);
VIR_FREE(serial);
virStorageEncryptionFree(encryption);
@@ -2713,6 +2739,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *model = NULL;
char *backend = NULL;
char *txmode = NULL;
+ char *ioeventfd = NULL;
char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
@@ -2802,6 +2829,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
backend = virXMLPropString(cur, "name");
txmode = virXMLPropString(cur, "txmode");
+ ioeventfd = virXMLPropString(cur, "ioeventfd");
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
filter = virXMLPropString(cur, "filter");
VIR_FREE(filterparams);
@@ -3018,6 +3046,16 @@ virDomainNetDefParseXML(virCapsPtr caps,
}
def->driver.virtio.txmode = m;
}
+ if (ioeventfd) {
+ int i;
+ if ((i = virDomainIoEventFdTypeFromString(ioeventfd)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown interface ioeventfd mode '%s'"),
+ ioeventfd);
+ goto error;
+ }
+ def->driver.virtio.ioeventfd = i;
+ }
}
if (filter != NULL) {
@@ -3057,6 +3095,7 @@ cleanup:
VIR_FREE(model);
VIR_FREE(backend);
VIR_FREE(txmode);
+ VIR_FREE(ioeventfd);
VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
@@ -8291,6 +8330,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
const char *iomode = virDomainDiskIoTypeToString(def->iomode);
+ const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd);
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -8322,7 +8362,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
" <disk type='%s' device='%s'>\n",
type, device);
- if (def->driverName || def->driverType || def->cachemode) {
+ if (def->driverName || def->driverType || def->cachemode ||
+ def->ioeventfd) {
virBufferAsprintf(buf, " <driver");
if (def->driverName)
virBufferAsprintf(buf, " name='%s'", def->driverName);
@@ -8334,6 +8375,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " error_policy='%s'", error_policy);
if (def->iomode)
virBufferAsprintf(buf, " io='%s'", iomode);
+ if (def->ioeventfd)
+ virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
virBufferAsprintf(buf, "/>\n");
}
@@ -8624,6 +8667,10 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " txmode='%s'",
virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
}
+ if (def->driver.virtio.ioeventfd) {
+ virBufferAsprintf(buf, " ioeventfd='%s'",
+ virDomainIoEventFdTypeToString(def->driver.virtio.ioeventfd));
+ }
virBufferAddLit(buf, "/>\n");
}
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ff5c28d..994ff91 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -206,6 +206,14 @@ enum virDomainDiskIo {
VIR_DOMAIN_DISK_IO_LAST
};
+enum virDomainIoEventFd {
+ VIR_DOMAIN_IO_EVENT_FD_DEFAULT = 0,
+ VIR_DOMAIN_IO_EVENT_FD_ON,
+ VIR_DOMAIN_IO_EVENT_FD_OFF,
+
+ VIR_DOMAIN_IO_EVENT_FD_LAST
+};
+
/* Stores the virtual disk configuration */
typedef struct _virDomainDiskDef virDomainDiskDef;
typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -225,6 +233,7 @@ struct _virDomainDiskDef {
int error_policy;
int bootIndex;
int iomode;
+ int ioeventfd;
unsigned int readonly : 1;
unsigned int shared : 1;
virDomainDeviceInfo info;
@@ -361,6 +370,7 @@ struct _virDomainNetDef {
struct {
enum virDomainNetBackendType name; /* which driver backend to use */
enum virDomainNetVirtioTxModeType txmode;
+ enum virDomainIoEventFd ioeventfd;
} virtio;
} driver;
union {
@@ -1554,6 +1564,7 @@ VIR_ENUM_DECL(virDomainDiskCache)
VIR_ENUM_DECL(virDomainDiskErrorPolicy)
VIR_ENUM_DECL(virDomainDiskProtocol)
VIR_ENUM_DECL(virDomainDiskIo)
+VIR_ENUM_DECL(virDomainIoEventFd)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 03d2ddb..5c8d272 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -292,6 +292,8 @@ virDomainHostdevDefFree;
virDomainHostdevModeTypeToString;
virDomainHostdevSubsysTypeToString;
virDomainInputDefFree;
+virDomainIoEventFdTypeFromString;
+virDomainIoEventFdTypeToString;
virDomainLeaseIndex;
virDomainLeaseInsert;
virDomainLeaseInsertPreAlloc;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 28c89b5..ad62a07 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -121,6 +121,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"device-qxl-vga",
"pci-multifunction", /* 60 */
+ "virtio-blk-pci.ioeventfd",
);
struct qemu_feature_flags {
@@ -1207,6 +1208,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags)
qemuCapsSet(flags, QEMU_CAPS_VIRTIO_TX_ALG);
if (strstr(str, "name \"qxl-vga\""))
qemuCapsSet(flags, QEMU_CAPS_DEVICE_QXL_VGA);
+ if (strstr(str, "virtio-blk-pci.ioeventfd"))
+ qemuCapsSet(flags, QEMU_CAPS_VIRTIO_IOEVENTFD);
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index e6d2fa3..0b9c8be 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -96,6 +96,7 @@ enum qemuCapsFlags {
QEMU_CAPS_VIRTIO_TX_ALG = 58, /* -device virtio-net-pci,tx=string */
QEMU_CAPS_DEVICE_QXL_VGA = 59, /* Is the primary and vga campatible qxl device named qxl-vga? */
QEMU_CAPS_PCI_MULTIFUNCTION = 60, /* -device multifunction=on|off */
+ QEMU_CAPS_VIRTIO_IOEVENTFD = 61, /* IOeventFD feature: virtio-{net|blk}-pci.ioeventfd=on/off */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 6346243..f7c06f8 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1287,6 +1287,16 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
return 0;
}
+static int
+qemuBuildIoEventFdStr(virBufferPtr buf,
+ enum virDomainIoEventFd use,
+ virBitmapPtr qemuCaps)
+{
+ if (use && qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD))
+ virBufferAsprintf(buf, ",ioeventfd=%s",
+ virDomainIoEventFdTypeToString(use));
+ return 0;
+}
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
@@ -1554,6 +1564,7 @@ qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
virBufferAddLit(&opt, "virtio-blk-pci");
+ qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
qemuBuildDeviceAddressStr(&opt, &disk->info, qemuCaps);
break;
case VIR_DOMAIN_DISK_BUS_USB:
@@ -1777,6 +1788,8 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
goto error;
}
}
+ if (usingVirtio)
+ qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps);
if (vlan == -1)
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
else
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 327a0c7..119e771 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -475,7 +475,8 @@ mymain(void)
QEMU_CAPS_CCID_PASSTHRU,
QEMU_CAPS_CHARDEV_SPICEVMC,
QEMU_CAPS_DEVICE_QXL_VGA,
- QEMU_CAPS_VIRTIO_TX_ALG);
+ QEMU_CAPS_VIRTIO_TX_ALG,
+ QEMU_CAPS_VIRTIO_IOEVENTFD);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args
new file mode 100644
index 0000000..c512f15
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.args
@@ -0,0 +1,11 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/qemu -S -M pc-0.13 -m 1024 -smp 1 -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi \
+-boot dc -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
+-drive file=/var/lib/libvirt/images/f14.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,ioeventfd=on,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-device virtio-net-pci,tx=bh,ioeventfd=off,vlan=0,id=net0,mac=52:54:00:e5:48:58,bus=pci.0,addr=0x3 \
+-net user,vlan=0,name=hostnet0 -serial pty -usb -vnc 127.0.0.1:-809 -std-vga \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml
new file mode 100644
index 0000000..c565c9f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-ioeventfd.xml
@@ -0,0 +1,50 @@
+<domain type='qemu'>
+ <name>test</name>
+ <memory>1048576</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-0.13'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2' ioeventfd='on'/>
+ <source file='/var/lib/libvirt/images/f14.img'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <source file='/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <interface type='user'>
+ <mac address='52:54:00:e5:48:58'/>
+ <model type='virtio'/>
+ <driver name='vhost' txmode='iothread' ioeventfd='off'/>
+ </interface>
+ <controller type='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </controller>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <graphics type='vnc' port='5091' autoport='no' listen='127.0.0.1'/>
+ <video>
+ <model type='vga' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index bd07efa..782664a 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -350,6 +350,10 @@ mymain(void)
DO_TEST("disk-aio", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_AIO,
QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT);
+ DO_TEST("disk-ioeventfd", false,
+ QEMU_CAPS_DRIVE, QEMU_CAPS_VIRTIO_IOEVENTFD,
+ QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE);
+
DO_TEST("graphics-vnc", false, NONE);
DO_TEST("graphics-vnc-socket", false, NONE);
--
1.7.5.rc3
2
2
[libvirt] [PATCH v4]: set and restore MAC address of a NIC when using PASSTHROUGH mode
by Gerhard Stenzel 22 Jun '11
by Gerhard Stenzel 22 Jun '11
22 Jun '11
Next try ..
The following patch addresses the problem that when a PASSTHROUGH
mode DIRECT NIC connection is made the MAC address of the NIC is
not automatically set and reset to the configured VM MAC and
back again.
The attached patch fixes this problem by setting and resetting the MAC
while remembering the previous setting while the VM is running.
This also works if libvirtd is restarted while the VM is running.
the patch passes make syntax-check
Signed-off-by: Dirk Herrendoerfer <d.herrendoerfer at herrendoerfer.name>
Signed-off-by: Gerhard Stenzel <gerhard.stenzel(a)de.ibm.com>
---
Index: libvirt/src/qemu/qemu_command.c
===================================================================
--- libvirt.orig/src/qemu/qemu_command.c
+++ libvirt/src/qemu/qemu_command.c
@@ -128,7 +128,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def
rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
net->data.direct.mode, vnet_hdr, def->uuid,
&net->data.direct.virtPortProfile, &res_ifname,
- vmop);
+ vmop, driver->stateDir);
if (rc >= 0) {
qemuAuditNetDevice(def, net, res_ifname, true);
VIR_FREE(net->ifname);
@@ -149,7 +149,9 @@ qemuPhysIfaceConnect(virDomainDefPtr def
if (err) {
VIR_FORCE_CLOSE(rc);
delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
- &net->data.direct.virtPortProfile);
+ net->data.direct.mode,
+ &net->data.direct.virtPortProfile,
+ driver->stateDir);
VIR_FREE(net->ifname);
}
}
Index: libvirt/src/qemu/qemu_process.c
===================================================================
--- libvirt.orig/src/qemu/qemu_process.c
+++ libvirt/src/qemu/qemu_process.c
@@ -2876,7 +2876,8 @@ void qemuProcessStop(struct qemud_driver
virDomainNetDefPtr net = def->nets[i];
if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
- &net->data.direct.virtPortProfile);
+ net->data.direct.mode,
+ &net->data.direct.virtPortProfile, driver->stateDir);
VIR_FREE(net->ifname);
}
}
Index: libvirt/src/util/macvtap.c
===================================================================
--- libvirt.orig/src/util/macvtap.c
+++ libvirt/src/util/macvtap.c
@@ -545,6 +545,104 @@ configMacvtapTap(int tapfd, int vnet_hdr
return 0;
}
+/**
+ * replaceMacAdress:
+ * @macaddress: new MAC address for interface
+ * @linkdev: name of interface
+ * @stateDir: directory to store old MAC address
+ *
+ * Returns 0 on success, -1 in case of fatal error, error code otherwise.
+ *
+ */
+static int
+replaceMacAdress(const unsigned char *macaddress,
+ const char *linkdev,
+ char *stateDir)
+{
+ unsigned char oldmac[6];
+ int rc;
+
+ rc = ifaceGetMacaddr(linkdev, oldmac);
+
+ if (rc) {
+ virReportSystemError(rc,
+ _("Getting MAC address from '%s' "
+ "to '%02x:%02x:%02x:%02x:%02x:%02x' failed."),
+ linkdev,
+ oldmac[0], oldmac[1], oldmac[2],
+ oldmac[3], oldmac[4], oldmac[5]);
+ } else {
+ char *path = NULL;
+ char macstr[VIR_MAC_STRING_BUFLEN];
+
+ if (virAsprintf(&path, "%s/%s",
+ stateDir,
+ linkdev) < 0) {
+ virReportOOMError();
+ return errno;
+ }
+ virFormatMacAddr(oldmac, macstr);
+ if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
+ virReportSystemError(errno, _("Unable to preserve mac for %s"),
+ linkdev);
+ return errno;
+ }
+ }
+
+ rc = ifaceSetMacaddr(linkdev, macaddress);
+ if (rc) {
+ virReportSystemError(errno,
+ _("Setting MAC address on '%s' to "
+ "'%02x:%02x:%02x:%02x:%02x:%02x' failed."),
+ linkdev,
+ macaddress[0], macaddress[1], macaddress[2],
+ macaddress[3], macaddress[4], macaddress[5]);
+ }
+ return rc;
+}
+
+/**
+ * restoreMacAddress:
+ * @linkdev: name of interface
+ * @stateDir: directory containing old MAC address
+ *
+ * Returns 0 on success, -1 in case of fatal error, error code otherwise.
+ *
+ */
+static int
+restoreMacAddress(const char *linkdev,
+ char *stateDir)
+{
+ int ret;
+ char *oldmacname = NULL;
+ char *macstr = NULL;
+ char *path = NULL;
+ unsigned char oldmac[6];
+
+ if (virAsprintf(&path, "%s/%s",
+ stateDir,
+ linkdev) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0) {
+ return errno;
+ }
+
+ if (virParseMacAddr(macstr, &oldmac[0]) != 0) {
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse MAC address from '%s'"),
+ oldmacname);
+ return -1;
+ }
+
+ /*reset mac and remove file-ignore results*/
+ ignore_value(ifaceSetMacaddr(linkdev, oldmac));
+ ignore_value(unlink(path));
+ VIR_FREE(macstr);
+ return 0;
+}
/**
* openMacvtapTap:
@@ -575,7 +673,8 @@ openMacvtapTap(const char *tgifname,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname,
- enum virVMOperationType vmOp)
+ enum virVMOperationType vmOp,
+ char *stateDir)
{
const char *type = "macvtap";
int c, rc;
@@ -589,6 +688,19 @@ openMacvtapTap(const char *tgifname,
VIR_DEBUG("%s: VM OPERATION: %s", __FUNCTION__, virVMOperationTypeToString(vmOp));
+ /** Note: When using PASSTHROUGH mode with MACVTAP devices the link
+ * device's MAC address must be set to the VMs MAC address. In
+ * order to not confuse the first switch or bridge in line this MAC
+ * address must be reset when the VM is shut down.
+ * This is especially important when using SRIOV capable cards that
+ * emulate their switch in firmware.
+ */
+ if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
+ if (replaceMacAdress(macaddress, linkdev, stateDir) != 0) {
+ return -1;
+ }
+ }
+
if (tgifname) {
if(ifaceGetIndex(false, tgifname, &ifindex) == 0) {
if (STRPREFIX(tgifname,
@@ -684,8 +796,14 @@ void
delMacvtap(const char *ifname,
const unsigned char *macaddr,
const char *linkdev,
- virVirtualPortProfileParamsPtr virtPortProfile)
+ int mode,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char *stateDir)
{
+ if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
+ restoreMacAddress(linkdev, stateDir);
+ }
+
if (ifname) {
vpDisassociatePortProfileId(ifname, macaddr,
linkdev,
Index: libvirt/src/util/macvtap.h
===================================================================
--- libvirt.orig/src/util/macvtap.h
+++ libvirt/src/util/macvtap.h
@@ -83,12 +83,15 @@ int openMacvtapTap(const char *ifname,
const unsigned char *vmuuid,
virVirtualPortProfileParamsPtr virtPortProfile,
char **res_ifname,
- enum virVMOperationType vmop);
+ enum virVMOperationType vmop,
+ char *stateDir);
void delMacvtap(const char *ifname,
const unsigned char *macaddress,
const char *linkdev,
- virVirtualPortProfileParamsPtr virtPortProfile);
+ int mode,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char *stateDir);
int vpAssociatePortProfileId(const char *macvtap_ifname,
const unsigned char *macvtap_macaddr,
Index: libvirt/src/qemu/qemu_hotplug.c
===================================================================
--- libvirt.orig/src/qemu/qemu_hotplug.c
+++ libvirt/src/qemu/qemu_hotplug.c
@@ -1610,7 +1610,9 @@ int qemuDomainDetachNetDevice(struct qem
#if WITH_MACVTAP
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev,
- &detach->data.direct.virtPortProfile);
+ detach->data.direct.mode,
+ &detach->data.direct.virtPortProfile,
+ driver->stateDir);
VIR_FREE(detach->ifname);
}
#endif
Index: libvirt/src/util/interface.c
===================================================================
--- libvirt.orig/src/util/interface.c
+++ libvirt/src/util/interface.c
@@ -390,3 +390,99 @@ ifaceGetVlanID(const char *vlanifname AT
return ENOSYS;
}
#endif /* __linux__ */
+
+/**
+ * ifaceGetMacaddr:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function gets the @macaddr for a given interface @ifname.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef __linux__
+int
+ifaceGetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ if (ioctl(fd, SIOCGIFHWADDR, (char *)&ifr) != 0)
+ return errno;
+
+ memcpy(macaddr, ifr.ifr_ifru.ifru_hwaddr.sa_data, VIR_MAC_BUFLEN);
+
+ return 0;
+}
+
+#else
+
+int
+ifaceGetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ return ENOSYS;
+}
+
+#endif /* __linux__ */
+
+/**
+ * ifaceSetMacaddr:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function sets the @macaddr for a given interface @ifname. This
+ * gets rid of the kernel's automatically assigned random MAC.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+#ifdef __linux__
+int
+ifaceSetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ const unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ /* To fill ifr.ifr_hdaddr.sa_family field */
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
+ return errno;
+
+ memcpy(ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN);
+
+ return ioctl(fd, SIOCSIFHWADDR, &ifr) == 0 ? 0 : errno;
+}
+
+#else
+
+int
+ifaceSetMacaddr(const char *ifname ATTRIBUTE_UNUSED,
+ const unsigned char *macaddr ATTRIBUTE_UNUSED)
+{
+ return ENOSYS;
+}
+
+#endif /* __linux__ */
Index: libvirt/src/util/interface.h
===================================================================
--- libvirt.orig/src/util/interface.h
+++ libvirt/src/util/interface.h
@@ -32,4 +32,8 @@ int ifaceGetIndex(bool reportError, cons
int ifaceGetVlanID(const char *vlanifname, int *vlanid);
+int ifaceSetMacaddr(const char *ifname, const unsigned char *macaddr);
+
+int ifaceGetMacaddr(const char *ifname, unsigned char *macaddr);
+
#endif /* __VIR_INTERFACE_H__ */
Index: libvirt/src/libvirt_private.syms
===================================================================
--- libvirt.orig/src/libvirt_private.syms
+++ libvirt/src/libvirt_private.syms
@@ -507,7 +507,9 @@ ifaceCheck;
ifaceCtrl;
ifaceGetFlags;
ifaceGetIndex;
+ifaceGetMacaddr;
ifaceGetVlanID;
+ifaceSetMacaddr;
ifaceIsUp;
===================================================================
Best regards,
Gerhard Stenzel
-------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
4
7
[libvirt] [PATCH 2/2] cleanup: make several interface functions commonly available
by Stefan Berger 21 Jun '11
by Stefan Berger 21 Jun '11
21 Jun '11
In a second cleanup step this patch makes several interface functions
from macvtap.c commonly available by moving them into interface.c and
prefixing their names with 'iface'. Those functions taking
Linux-specific structures as parameters are only visible on Linux.
ifaceRestoreMacAddress returns the return code from the ifaceSetMacAddr
call and display an error message if setting the MAC address did not
work. The caller is unchanged and still ignores the return code (which
is ok).
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/libvirt_private.syms | 8
src/util/interface.c | 590
+++++++++++++++++++++++++++++++++++++++++++++++
src/util/interface.h | 33 ++
src/util/macvtap.c | 495 ---------------------------------------
4 files changed, 640 insertions(+), 486 deletions(-)
Index: libvirt-acl/src/util/interface.c
===================================================================
--- libvirt-acl.orig/src/util/interface.c
+++ libvirt-acl/src/util/interface.c
@@ -27,6 +27,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <fcntl.h>
#ifdef __linux__
# include <linux/if.h>
@@ -40,6 +41,10 @@
#include "interface.h"
#include "virterror_internal.h"
#include "files.h"
+#include "memory.h"
+#include "netlink.h"
+
+#define VIR_FROM_THIS VIR_FROM_NET
#define ifaceError(code, ...) \
virReportErrorHelper(VIR_FROM_NET, code, __FILE__, \
@@ -486,3 +491,588 @@ ifaceSetMacaddr(const char *ifname ATTRI
}
#endif /* __linux__ */
+
+
+/**
+ * ifaceLinkAdd
+ *
+ * @type: The type of device, i.e., "macvtap"
+ * @macaddress: The MAC address of the device
+ * @macaddrsize: The size of the MAC address, typically '6'
+ * @ifname: The name the interface is supposed to have; optional parameter
+ * @srcdev: The name of the 'link' device
+ * @macvlan_mode: The macvlan mode to use
+ * @retry: Pointer to integer that will be '1' upon return if an interface
+ * with the same name already exists and it is worth to try
+ * again with a different name
+ *
+ * Create a macvtap device with the given properties.
+ *
+ * Returns 0 on success, -1 on fatal error.
+ */
+#if __linux__
+int
+ifaceMacvtapLinkAdd(const char *type,
+ const unsigned char *macaddress, int macaddrsize,
+ const char *ifname,
+ const char *srcdev,
+ uint32_t macvlan_mode,
+ int *retry)
+{
+ int rc = 0;
+ struct nlmsghdr *resp;
+ struct nlmsgerr *err;
+ struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
+ int ifindex;
+ unsigned char *recvbuf = NULL;
+ unsigned int recvbuflen;
+ struct nl_msg *nl_msg;
+ struct nlattr *linkinfo, *info_data;
+
+ if (ifaceGetIndex(true, srcdev, &ifindex) != 0)
+ return -1;
+
+ *retry = 0;
+
+ nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+ if (!nl_msg) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
+ goto buffer_too_small;
+
+ if (nla_put_u32(nl_msg, IFLA_LINK, ifindex) < 0)
+ goto buffer_too_small;
+
+ if (nla_put(nl_msg, IFLA_ADDRESS, macaddrsize, macaddress) < 0)
+ goto buffer_too_small;
+
+ if (ifname &&
+ nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
+ goto buffer_too_small;
+
+ if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
+ goto buffer_too_small;
+
+ if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0)
+ goto buffer_too_small;
+
+ if (macvlan_mode > 0) {
+ if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
+ goto buffer_too_small;
+
+ if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(macvlan_mode),
+ &macvlan_mode) < 0)
+ goto buffer_too_small;
+
+ nla_nest_end(nl_msg, info_data);
+ }
+
+ nla_nest_end(nl_msg, linkinfo);
+
+ if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) {
+ rc = -1;
+ goto err_exit;
+ }
+
+ if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
+ goto malformed_resp;
+
+ resp = (struct nlmsghdr *)recvbuf;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
+ goto malformed_resp;
+
+ switch (err->error) {
+
+ case 0:
+ break;
+
+ case -EEXIST:
+ *retry = 1;
+ rc = -1;
+ break;
+
+ default:
+ virReportSystemError(-err->error,
+ _("error creating %s type of interface"),
+ type);
+ rc = -1;
+ }
+ break;
+
+ case NLMSG_DONE:
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+err_exit:
+ nlmsg_free(nl_msg);
+
+ VIR_FREE(recvbuf);
+
+ return rc;
+
+malformed_resp:
+ nlmsg_free(nl_msg);
+
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(recvbuf);
+ return -1;
+
+buffer_too_small:
+ nlmsg_free(nl_msg);
+
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("allocated netlink buffer is too small"));
+ return -1;
+}
+
+#else
+
+int
+ifaceMacvtapLinkAdd(const char *type ATTRIBUTE_UNUSED,
+ const unsigned char *macaddress ATTRIBUTE_UNUSED,
+ int macaddrsize ATTRIBUTE_UNUSED,
+ const char *ifname ATTRIBUTE_UNUSED,
+ const char *srcdev ATTRIBUTE_UNUSED,
+ uint32_t macvlan_mode ATTRIBUTE_UNUSED,
+ int *retry ATTRIBUTE_UNUSED)
+{
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ifaceMacvtapLinkAdd is not supported on non-linux
platforms"));
+ return -1;
+}
+
+#endif
+
+
+/**
+ * ifaceLinkDel
+ *
+ * @ifname: Name of the interface
+ *
+ * Tear down an interface with the given name.
+ *
+ * Returns 0 on success, -1 on fatal error.
+ */
+#if __linux__
+int
+ifaceLinkDel(const char *ifname)
+{
+ int rc = 0;
+ struct nlmsghdr *resp;
+ struct nlmsgerr *err;
+ struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
+ unsigned char *recvbuf = NULL;
+ unsigned int recvbuflen;
+ struct nl_msg *nl_msg;
+
+ nl_msg = nlmsg_alloc_simple(RTM_DELLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+ if (!nl_msg) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
+ goto buffer_too_small;
+
+ if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
+ goto buffer_too_small;
+
+ if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) {
+ rc = -1;
+ goto err_exit;
+ }
+
+ if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
+ goto malformed_resp;
+
+ resp = (struct nlmsghdr *)recvbuf;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
+ goto malformed_resp;
+
+ if (err->error) {
+ virReportSystemError(-err->error,
+ _("error destroying %s interface"),
+ ifname);
+ rc = -1;
+ }
+ break;
+
+ case NLMSG_DONE:
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+err_exit:
+ nlmsg_free(nl_msg);
+
+ VIR_FREE(recvbuf);
+
+ return rc;
+
+malformed_resp:
+ nlmsg_free(nl_msg);
+
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(recvbuf);
+ return -1;
+
+buffer_too_small:
+ nlmsg_free(nl_msg);
+
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("allocated netlink buffer is too small"));
+ return -1;
+}
+
+#else
+
+int
+ifaceLinkDel(const char *ifname ATTRIBUTE_UNUSED)
+{
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ifaceLinkDel is not supported on non-linux platforms"));
+ return -1;
+}
+
+#endif
+
+
+#if __linux__
+static struct nla_policy ifla_policy[IFLA_MAX + 1] =
+{
+ [IFLA_VF_PORTS] = { .type = NLA_NESTED },
+};
+
+/**
+ * ifaceMacvtapLinkDump
+ *
+ * @nltarget_kernel: whether to send the message to the kernel or another
+ * process
+ * @ifname: The name of the interface; only use if ifindex < 0
+ * @ifindex: The interface index; may be < 0 if ifname is given
+ * @nlattr: pointer to a pointer of netlink attributes that will contain
+ * the results
+ * @recvbuf: Pointer to the buffer holding the returned netlink response
+ * message; free it, once not needed anymore
+ * @getPidFunc: Pointer to a function that will be invoked if the kernel
+ * is not the target of the netlink message but it is to be
+ * sent to another process.
+ *
+ * Get information about an interface given its name or index.
+ *
+ * Returns 0 on success, -1 on fatal error.
+ */
+int
+ifaceMacvtapLinkDump(bool nltarget_kernel, const char *ifname, int ifindex,
+ struct nlattr **tb, unsigned char **recvbuf,
+ uint32_t (*getPidFunc)(void))
+{
+ int rc = 0;
+ struct nlmsghdr *resp;
+ struct nlmsgerr *err;
+ struct ifinfomsg ifinfo = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = ifindex
+ };
+ unsigned int recvbuflen;
+ uint32_t pid = 0;
+ struct nl_msg *nl_msg;
+
+ *recvbuf = NULL;
+
+ nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
+ if (!nl_msg) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
+ goto buffer_too_small;
+
+ if (ifindex < 0 && ifname) {
+ if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
+ goto buffer_too_small;
+ }
+
+ if (!nltarget_kernel) {
+ pid = getPidFunc();
+ if (pid == 0) {
+ rc = -1;
+ goto err_exit;
+ }
+ }
+
+ if (nlComm(nl_msg, recvbuf, &recvbuflen, pid) < 0) {
+ rc = -1;
+ goto err_exit;
+ }
+
+ if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL)
+ goto malformed_resp;
+
+ resp = (struct nlmsghdr *)*recvbuf;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
+ goto malformed_resp;
+
+ if (err->error) {
+ virReportSystemError(-err->error,
+ _("error dumping %s (%d) interface"),
+ ifname, ifindex);
+ rc = -1;
+ }
+ break;
+
+ case GENL_ID_CTRL:
+ case NLMSG_DONE:
+ if (nlmsg_parse(resp, sizeof(struct ifinfomsg),
+ tb, IFLA_MAX, ifla_policy)) {
+ goto malformed_resp;
+ }
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+ if (rc != 0)
+ VIR_FREE(*recvbuf);
+
+err_exit:
+ nlmsg_free(nl_msg);
+
+ return rc;
+
+malformed_resp:
+ nlmsg_free(nl_msg);
+
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(*recvbuf);
+ return -1;
+
+buffer_too_small:
+ nlmsg_free(nl_msg);
+
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("allocated netlink buffer is too small"));
+ return -1;
+}
+
+#endif
+
+
+/**
+ * ifaceGetNthParent
+ *
+ * @ifindex : the index of the interface or -1 if ifname is given
+ * @ifname : the name of the interface; ignored if ifindex is valid
+ * @nthParent : the nth parent interface to get
+ * @parent_ifindex : pointer to int
+ * @parent_ifname : pointer to buffer of size IFNAMSIZ
+ * @nth : the nth parent that is actually returned; if for example eth0.100
+ * was given and the 100th parent is to be returned, then eth0 will
+ * most likely be returned with nth set to 1 since the chain does
+ * not have more interfaces
+ *
+ * Get the nth parent interface of the given interface. 0 is the interface
+ * itself.
+ *
+ * Return 0 on success, != 0 otherwise
+ */
+#if __linux__
+int
+ifaceGetNthParent(int ifindex, const char *ifname, unsigned int nthParent,
+ int *parent_ifindex, char *parent_ifname,
+ unsigned int *nth)
+{
+ int rc;
+ struct nlattr *tb[IFLA_MAX + 1] = { NULL, };
+ unsigned char *recvbuf = NULL;
+ bool end = false;
+ unsigned int i = 0;
+
+ *nth = 0;
+
+ if (ifindex <= 0 && ifaceGetIndex(true, ifname, &ifindex) != 0)
+ return 1;
+
+ while (!end && i <= nthParent) {
+ rc = ifaceMacvtapLinkDump(true, ifname, ifindex, tb, &recvbuf,
NULL);
+ if (rc)
+ break;
+
+ if (tb[IFLA_IFNAME]) {
+ if (!virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]),
+ IFNAMSIZ)) {
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("buffer for root interface name is too
small"));
+ VIR_FREE(recvbuf);
+ return 1;
+ }
+ *parent_ifindex = ifindex;
+ }
+
+ if (tb[IFLA_LINK]) {
+ ifindex = *(int *)RTA_DATA(tb[IFLA_LINK]);
+ ifname = NULL;
+ } else
+ end = true;
+
+ VIR_FREE(recvbuf);
+
+ i++;
+ }
+
+ if (nth)
+ *nth = i - 1;
+
+ return rc;
+}
+
+#else
+
+int
+ifaceGetNthParent(int ifindex ATTRIBUTE_UNUSED,
+ const char *ifname ATTRIBUTE_UNUSED,
+ unsigned int nthParent ATTRIBUTE_UNUSED,
+ int *parent_ifindex ATTRIBUTE_UNUSED,
+ char *parent_ifname ATTRIBUTE_UNUSED,
+ unsigned int *nth ATTRIBUTE_UNUSED)
+{
+ ifaceError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ifaceGetNthParent is not supported on non-linux
platforms"));
+ return -1;
+}
+
+#endif
+
+/**
+ * ifaceReplaceMacAddress:
+ * @macaddress: new MAC address for interface
+ * @linkdev: name of interface
+ * @stateDir: directory to store old MAC address
+ *
+ * Returns 0 on success, -1 in case of fatal error, error code otherwise.
+ *
+ */
+int
+ifaceReplaceMacAddress(const unsigned char *macaddress,
+ const char *linkdev,
+ const char *stateDir)
+{
+ unsigned char oldmac[6];
+ int rc;
+
+ rc = ifaceGetMacaddr(linkdev, oldmac);
+
+ if (rc) {
+ virReportSystemError(rc,
+ _("Getting MAC address from '%s' "
+ "to '%02x:%02x:%02x:%02x:%02x:%02x'
failed."),
+ linkdev,
+ oldmac[0], oldmac[1], oldmac[2],
+ oldmac[3], oldmac[4], oldmac[5]);
+ } else {
+ char *path = NULL;
+ char macstr[VIR_MAC_STRING_BUFLEN];
+
+ if (virAsprintf(&path, "%s/%s",
+ stateDir,
+ linkdev) < 0) {
+ virReportOOMError();
+ return errno;
+ }
+ virFormatMacAddr(oldmac, macstr);
+ if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
+ virReportSystemError(errno, _("Unable to preserve mac for %s"),
+ linkdev);
+ return errno;
+ }
+ }
+
+ rc = ifaceSetMacaddr(linkdev, macaddress);
+ if (rc) {
+ virReportSystemError(rc,
+ _("Setting MAC address on '%s' to "
+ "'%02x:%02x:%02x:%02x:%02x:%02x' failed."),
+ linkdev,
+ macaddress[0], macaddress[1], macaddress[2],
+ macaddress[3], macaddress[4], macaddress[5]);
+ }
+ return rc;
+}
+
+/**
+ * ifaceRestoreMacAddress:
+ * @linkdev: name of interface
+ * @stateDir: directory containing old MAC address
+ *
+ * Returns 0 on success, -1 in case of fatal error, error code otherwise.
+ *
+ */
+int
+ifaceRestoreMacAddress(const char *linkdev,
+ const char *stateDir)
+{
+ int rc;
+ char *oldmacname = NULL;
+ char *macstr = NULL;
+ char *path = NULL;
+ unsigned char oldmac[6];
+
+ if (virAsprintf(&path, "%s/%s",
+ stateDir,
+ linkdev) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0) {
+ return errno;
+ }
+
+ if (virParseMacAddr(macstr, &oldmac[0]) != 0) {
+ ifaceError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse MAC address from '%s'"),
+ oldmacname);
+ return -1;
+ }
+
+ /*reset mac and remove file-ignore results*/
+ rc = ifaceSetMacaddr(linkdev, oldmac);
+ if (rc) {
+ virReportSystemError(rc,
+ _("Setting MAC address on '%s' to "
+ "'%02x:%02x:%02x:%02x:%02x:%02x' failed."),
+ linkdev,
+ oldmac[0], oldmac[1], oldmac[2],
+ oldmac[3], oldmac[4], oldmac[5]);
+ }
+ ignore_value(unlink(path));
+ VIR_FREE(macstr);
+ return rc;
+}
Index: libvirt-acl/src/util/interface.h
===================================================================
--- libvirt-acl.orig/src/util/interface.h
+++ libvirt-acl/src/util/interface.h
@@ -10,6 +10,13 @@
#ifndef __VIR_INTERFACE_H__
# define __VIR_INTERFACE_H__
+# include <stdint.h>
+
+# if __linux__
+# include <sys/socket.h>
+# include <linux/netlink.h>
+# endif
+
# include "datatypes.h"
int ifaceGetFlags(const char *name, short *flags);
@@ -36,4 +43,30 @@ int ifaceSetMacaddr(const char *ifname,
int ifaceGetMacaddr(const char *ifname, unsigned char *macaddr);
+int ifaceMacvtapLinkAdd(const char *type,
+ const unsigned char *macaddress, int macaddrsize,
+ const char *ifname,
+ const char *srcdev,
+ uint32_t macvlan_mode,
+ int *retry);
+
+int ifaceLinkDel(const char *ifname);
+
+# if __linux__
+int ifaceMacvtapLinkDump(bool nltarget_kernel, const char *ifname, int
ifindex,
+ struct nlattr **tb, unsigned char **recvbuf,
+ uint32_t (*getPidFunc)(void));
+# endif
+
+int ifaceGetNthParent(int ifindex, const char *ifname, unsigned int
nthParent,
+ int *parent_ifindex, char *parent_ifname,
+ unsigned int *nth);
+
+int ifaceReplaceMacAddress(const unsigned char *macaddress,
+ const char *linkdev,
+ const char *stateDir);
+
+int ifaceRestoreMacAddress(const char *linkdev,
+ const char *stateDir);
+
#endif /* __VIR_INTERFACE_H__ */
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -95,212 +95,6 @@ enum virVirtualPortOp {
# if WITH_MACVTAP
-static int
-link_add(const char *type,
- const unsigned char *macaddress, int macaddrsize,
- const char *ifname,
- const char *srcdev,
- uint32_t macvlan_mode,
- int *retry)
-{
- int rc = 0;
- struct nlmsghdr *resp;
- struct nlmsgerr *err;
- struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
- int ifindex;
- unsigned char *recvbuf = NULL;
- unsigned int recvbuflen;
- struct nl_msg *nl_msg;
- struct nlattr *linkinfo, *info_data;
-
- if (ifaceGetIndex(true, srcdev, &ifindex) != 0)
- return -1;
-
- *retry = 0;
-
- nl_msg = nlmsg_alloc_simple(RTM_NEWLINK,
- NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
- if (!nl_msg) {
- virReportOOMError();
- return -1;
- }
-
- if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
- goto buffer_too_small;
-
- if (nla_put_u32(nl_msg, IFLA_LINK, ifindex) < 0)
- goto buffer_too_small;
-
- if (nla_put(nl_msg, IFLA_ADDRESS, macaddrsize, macaddress) < 0)
- goto buffer_too_small;
-
- if (ifname &&
- nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
- goto buffer_too_small;
-
- if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
- goto buffer_too_small;
-
- if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0)
- goto buffer_too_small;
-
- if (macvlan_mode > 0) {
- if (!(info_data = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
- goto buffer_too_small;
-
- if (nla_put(nl_msg, IFLA_MACVLAN_MODE, sizeof(macvlan_mode),
- &macvlan_mode) < 0)
- goto buffer_too_small;
-
- nla_nest_end(nl_msg, info_data);
- }
-
- nla_nest_end(nl_msg, linkinfo);
-
- if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) {
- rc = -1;
- goto err_exit;
- }
-
- if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
- goto malformed_resp;
-
- resp = (struct nlmsghdr *)recvbuf;
-
- switch (resp->nlmsg_type) {
- case NLMSG_ERROR:
- err = (struct nlmsgerr *)NLMSG_DATA(resp);
- if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
- goto malformed_resp;
-
- switch (err->error) {
-
- case 0:
- break;
-
- case -EEXIST:
- *retry = 1;
- rc = -1;
- break;
-
- default:
- virReportSystemError(-err->error,
- _("error creating %s type of interface"),
- type);
- rc = -1;
- }
- break;
-
- case NLMSG_DONE:
- break;
-
- default:
- goto malformed_resp;
- }
-
-err_exit:
- nlmsg_free(nl_msg);
-
- VIR_FREE(recvbuf);
-
- return rc;
-
-malformed_resp:
- nlmsg_free(nl_msg);
-
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("malformed netlink response message"));
- VIR_FREE(recvbuf);
- return -1;
-
-buffer_too_small:
- nlmsg_free(nl_msg);
-
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("allocated netlink buffer is too small"));
- return -1;
-}
-
-
-static int
-link_del(const char *ifname)
-{
- int rc = 0;
- struct nlmsghdr *resp;
- struct nlmsgerr *err;
- struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
- unsigned char *recvbuf = NULL;
- unsigned int recvbuflen;
- struct nl_msg *nl_msg;
-
- nl_msg = nlmsg_alloc_simple(RTM_DELLINK,
- NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
- if (!nl_msg) {
- virReportOOMError();
- return -1;
- }
-
- if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
- goto buffer_too_small;
-
- if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
- goto buffer_too_small;
-
- if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) {
- rc = -1;
- goto err_exit;
- }
-
- if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
- goto malformed_resp;
-
- resp = (struct nlmsghdr *)recvbuf;
-
- switch (resp->nlmsg_type) {
- case NLMSG_ERROR:
- err = (struct nlmsgerr *)NLMSG_DATA(resp);
- if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
- goto malformed_resp;
-
- if (err->error) {
- virReportSystemError(-err->error,
- _("error destroying %s interface"),
- ifname);
- rc = -1;
- }
- break;
-
- case NLMSG_DONE:
- break;
-
- default:
- goto malformed_resp;
- }
-
-err_exit:
- nlmsg_free(nl_msg);
-
- VIR_FREE(recvbuf);
-
- return rc;
-
-malformed_resp:
- nlmsg_free(nl_msg);
-
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("malformed netlink response message"));
- VIR_FREE(recvbuf);
- return -1;
-
-buffer_too_small:
- nlmsg_free(nl_msg);
-
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("allocated netlink buffer is too small"));
- return -1;
-}
-
-
/* Open the macvtap's tap device.
* @ifname: Name of the macvtap interface
* @retries : Number of retries in case udev for example may need to be
@@ -450,104 +244,6 @@ configMacvtapTap(int tapfd, int vnet_hdr
}
/**
- * replaceMacAdress:
- * @macaddress: new MAC address for interface
- * @linkdev: name of interface
- * @stateDir: directory to store old MAC address
- *
- * Returns 0 on success, -1 in case of fatal error, error code otherwise.
- *
- */
-static int
-replaceMacAdress(const unsigned char *macaddress,
- const char *linkdev,
- char *stateDir)
-{
- unsigned char oldmac[6];
- int rc;
-
- rc = ifaceGetMacaddr(linkdev, oldmac);
-
- if (rc) {
- virReportSystemError(rc,
- _("Getting MAC address from '%s' "
- "to '%02x:%02x:%02x:%02x:%02x:%02x'
failed."),
- linkdev,
- oldmac[0], oldmac[1], oldmac[2],
- oldmac[3], oldmac[4], oldmac[5]);
- } else {
- char *path = NULL;
- char macstr[VIR_MAC_STRING_BUFLEN];
-
- if (virAsprintf(&path, "%s/%s",
- stateDir,
- linkdev) < 0) {
- virReportOOMError();
- return errno;
- }
- virFormatMacAddr(oldmac, macstr);
- if (virFileWriteStr(path, macstr, O_CREAT|O_TRUNC|O_WRONLY) < 0) {
- virReportSystemError(errno, _("Unable to preserve mac for %s"),
- linkdev);
- return errno;
- }
- }
-
- rc = ifaceSetMacaddr(linkdev, macaddress);
- if (rc) {
- virReportSystemError(errno,
- _("Setting MAC address on '%s' to "
- "'%02x:%02x:%02x:%02x:%02x:%02x' failed."),
- linkdev,
- macaddress[0], macaddress[1], macaddress[2],
- macaddress[3], macaddress[4], macaddress[5]);
- }
- return rc;
-}
-
-/**
- * restoreMacAddress:
- * @linkdev: name of interface
- * @stateDir: directory containing old MAC address
- *
- * Returns 0 on success, -1 in case of fatal error, error code otherwise.
- *
- */
-static int
-restoreMacAddress(const char *linkdev,
- char *stateDir)
-{
- char *oldmacname = NULL;
- char *macstr = NULL;
- char *path = NULL;
- unsigned char oldmac[6];
-
- if (virAsprintf(&path, "%s/%s",
- stateDir,
- linkdev) < 0) {
- virReportOOMError();
- return -1;
- }
-
- if (virFileReadAll(path, VIR_MAC_STRING_BUFLEN, &macstr) < 0) {
- return errno;
- }
-
- if (virParseMacAddr(macstr, &oldmac[0]) != 0) {
- macvtapError(VIR_ERR_INTERNAL_ERROR,
- _("Cannot parse MAC address from '%s'"),
- oldmacname);
- return -1;
- }
-
- /*reset mac and remove file-ignore results*/
- ignore_value(ifaceSetMacaddr(linkdev, oldmac));
- ignore_value(unlink(path));
- VIR_FREE(macstr);
- return 0;
-}
-
-/**
* openMacvtapTap:
* Create an instance of a macvtap device and open its tap character
* device.
@@ -599,7 +295,7 @@ openMacvtapTap(const char *tgifname,
* emulate their switch in firmware.
*/
if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
- if (replaceMacAdress(macaddress, linkdev, stateDir) != 0) {
+ if (ifaceReplaceMacAddress(macaddress, linkdev, stateDir) != 0) {
return -1;
}
}
@@ -615,8 +311,8 @@ openMacvtapTap(const char *tgifname,
return -1;
}
cr_ifname = tgifname;
- rc = link_add(type, macaddress, 6, tgifname, linkdev,
- macvtapMode, &do_retry);
+ rc = ifaceMacvtapLinkAdd(type, macaddress, 6, tgifname, linkdev,
+ macvtapMode, &do_retry);
if (rc)
return -1;
} else {
@@ -625,8 +321,8 @@ create_name:
for (c = 0; c < 8192; c++) {
snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c);
if (ifaceGetIndex(false, ifname, &ifindex) == ENODEV) {
- rc = link_add(type, macaddress, 6, ifname, linkdev,
- macvtapMode, &do_retry);
+ rc = ifaceMacvtapLinkAdd(type, macaddress, 6, ifname,
linkdev,
+ macvtapMode, &do_retry);
if (rc == 0)
break;
@@ -679,7 +375,7 @@ disassociate_exit:
vmOp);
link_del_exit:
- link_del(cr_ifname);
+ ifaceLinkDel(cr_ifname);
return rc;
}
@@ -704,7 +400,7 @@ delMacvtap(const char *ifname,
char *stateDir)
{
if (mode == VIR_DOMAIN_NETDEV_MACVTAP_MODE_PASSTHRU) {
- restoreMacAddress(linkdev, stateDir);
+ ifaceRestoreMacAddress(linkdev, stateDir);
}
if (ifname) {
@@ -712,7 +408,7 @@ delMacvtap(const char *ifname,
linkdev,
virtPortProfile,
VIR_VM_OP_DESTROY);
- link_del(ifname);
+ ifaceLinkDel(ifname);
}
}
@@ -720,11 +416,6 @@ delMacvtap(const char *ifname,
# ifdef IFLA_PORT_MAX
-static struct nla_policy ifla_policy[IFLA_MAX + 1] =
-{
- [IFLA_VF_PORTS] = { .type = NLA_NESTED },
-};
-
static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] =
{
[IFLA_PORT_RESPONSE] = { .type = NLA_U16 },
@@ -764,173 +455,6 @@ getLldpadPid(void) {
}
-static int
-link_dump(bool nltarget_kernel, const char *ifname, int ifindex,
- struct nlattr **tb, unsigned char **recvbuf)
-{
- int rc = 0;
- struct nlmsghdr *resp;
- struct nlmsgerr *err;
- struct ifinfomsg ifinfo = {
- .ifi_family = AF_UNSPEC,
- .ifi_index = ifindex
- };
- unsigned int recvbuflen;
- uint32_t pid = 0;
- struct nl_msg *nl_msg;
-
- *recvbuf = NULL;
-
- nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
- if (!nl_msg) {
- virReportOOMError();
- return -1;
- }
-
- if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
- goto buffer_too_small;
-
- if (ifindex < 0 && ifname) {
- if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
- goto buffer_too_small;
- }
-
- if (!nltarget_kernel) {
- pid = getLldpadPid();
- if (pid == 0) {
- rc = -1;
- goto err_exit;
- }
- }
-
- if (nlComm(nl_msg, recvbuf, &recvbuflen, pid) < 0) {
- rc = -1;
- goto err_exit;
- }
-
- if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL)
- goto malformed_resp;
-
- resp = (struct nlmsghdr *)*recvbuf;
-
- switch (resp->nlmsg_type) {
- case NLMSG_ERROR:
- err = (struct nlmsgerr *)NLMSG_DATA(resp);
- if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
- goto malformed_resp;
-
- if (err->error) {
- virReportSystemError(-err->error,
- _("error dumping %s (%d) interface"),
- ifname, ifindex);
- rc = -1;
- }
- break;
-
- case GENL_ID_CTRL:
- case NLMSG_DONE:
- if (nlmsg_parse(resp, sizeof(struct ifinfomsg),
- tb, IFLA_MAX, ifla_policy)) {
- goto malformed_resp;
- }
- break;
-
- default:
- goto malformed_resp;
- }
-
- if (rc != 0)
- VIR_FREE(*recvbuf);
-
-err_exit:
- nlmsg_free(nl_msg);
-
- return rc;
-
-malformed_resp:
- nlmsg_free(nl_msg);
-
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("malformed netlink response message"));
- VIR_FREE(*recvbuf);
- return -1;
-
-buffer_too_small:
- nlmsg_free(nl_msg);
-
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("allocated netlink buffer is too small"));
- return -1;
-}
-
-
-/**
- * ifaceGetNthParent
- *
- * @ifindex : the index of the interface or -1 if ifname is given
- * @ifname : the name of the interface; ignored if ifindex is valid
- * @nthParent : the nth parent interface to get
- * @parent_ifindex : pointer to int
- * @parent_ifname : pointer to buffer of size IFNAMSIZ
- * @nth : the nth parent that is actually returned; if for example eth0.100
- * was given and the 100th parent is to be returned, then eth0 will
- * most likely be returned with nth set to 1 since the chain does
- * not have more interfaces
- *
- * Get the nth parent interface of the given interface. 0 is the interface
- * itself.
- *
- * Return 0 on success, != 0 otherwise
- */
-static int
-ifaceGetNthParent(int ifindex, const char *ifname, unsigned int nthParent,
- int *parent_ifindex, char *parent_ifname,
- unsigned int *nth)
-{
- int rc;
- struct nlattr *tb[IFLA_MAX + 1] = { NULL, };
- unsigned char *recvbuf = NULL;
- bool end = false;
- unsigned int i = 0;
-
- *nth = 0;
-
- if (ifindex <= 0 && ifaceGetIndex(true, ifname, &ifindex) != 0)
- return 1;
-
- while (!end && i <= nthParent) {
- rc = link_dump(true, ifname, ifindex, tb, &recvbuf);
- if (rc)
- break;
-
- if (tb[IFLA_IFNAME]) {
- if (!virStrcpy(parent_ifname, (char*)RTA_DATA(tb[IFLA_IFNAME]),
- IFNAMSIZ)) {
- macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("buffer for root interface name is too
small"));
- VIR_FREE(recvbuf);
- return 1;
- }
- *parent_ifindex = ifindex;
- }
-
- if (tb[IFLA_LINK]) {
- ifindex = *(int *)RTA_DATA(tb[IFLA_LINK]);
- ifname = NULL;
- } else
- end = true;
-
- VIR_FREE(recvbuf);
-
- i++;
- }
-
- if (nth)
- *nth = i - 1;
-
- return rc;
-}
-
/**
* getPortProfileStatus
*
@@ -1258,7 +782,8 @@ doPortProfileOpCommon(bool nltarget_kern
}
while (--repeats >= 0) {
- rc = link_dump(nltarget_kernel, NULL, ifindex, tb, &recvbuf);
+ rc = ifaceMacvtapLinkDump(nltarget_kernel, NULL, ifindex, tb,
+ &recvbuf, getLldpadPid);
if (rc)
goto err_exit;
rc = getPortProfileStatus(tb, vf, instanceId, nltarget_kernel,
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -499,9 +499,15 @@ ifaceCtrl;
ifaceGetFlags;
ifaceGetIndex;
ifaceGetMacaddr;
+ifaceGetNthParent;
ifaceGetVlanID;
-ifaceSetMacaddr;
ifaceIsUp;
+ifaceLinkDel;
+ifaceMacvtapLinkAdd;
+ifaceMacvtapLinkDump;
+ifaceReplaceMacAddress;
+ifaceRestoreMacaddress;
+ifaceSetMacaddr;
# interface_conf.h
2
1
21 Jun '11
When building for newer Fedora or RHEL, take advantage of the
newer netcf packaging to guarantee interface snapshot support.
* libvirt.spec.in (BuildRequires): Bump minimum version on
platforms that support netcf 0.1.8.
---
I don't think we need an explicit 'Requires: netcf-libs >= 0.1.8' line
for the runtime dependency, since netcf uses versioned symbols.
I'm not sure whether F16 was the right target for requiring 0.1.8,
or whether we should also try to include F15 (but 0.1.8 has not yet
been built for F15).
libvirt.spec.in | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 75b145a..11b8591 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -424,8 +424,12 @@ BuildRequires: libcap-ng-devel >= 0.5.0
BuildRequires: libssh2-devel
%endif
%if %{with_netcf}
+%if 0%{?fedora} >= 16 || 0%{?rhel} >= 6
+BuildRequires: netcf-devel >= 0.1.8
+%else
BuildRequires: netcf-devel >= 0.1.4
%endif
+%endif
%if %{with_esx}
%if 0%{?fedora} >= 9 || 0%{?rhel} >= 6
BuildRequires: libcurl-devel
--
1.7.4.4
2
2
https://bugzilla.redhat.com/show_bug.cgi?id=682121
Gettext reserves the empty string for internal use, and it must
not be passed through _(). We were violating this for commands
that (for whatever reason) used "" for their description.
* tools/virsh.c (vshCmddefHelp): Don't translate empty string.
Reported by Tatsuo Kawasaki.
---
tools/virsh.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index a315f05..bdd5005 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -12113,7 +12113,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
vshError(ctl, _("command '%s' doesn't exist"), cmdname);
return false;
} else {
- const char *desc = _(vshCmddefGetInfo(def, "desc"));
+ /* Don't translate desc until after we know it isn't "". */
+ const char *desc = vshCmddefGetInfo(def, "desc");
const char *help = _(vshCmddefGetInfo(def, "help"));
char buf[256];
uint32_t opts_need_arg;
@@ -12167,7 +12168,7 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
if (desc[0]) {
/* Print the description only if it's not empty. */
fputs(_("\n DESCRIPTION\n"), stdout);
- fprintf(stdout, " %s\n", desc);
+ fprintf(stdout, " %s\n", _(desc));
}
if (def->opts) {
--
1.7.4.4
3
3
21 Jun '11
Hello everybody.
it's been a rather long time since the first release of libvirt-php
bindings however there are many new features so I've decided to release
a new version of libvirt-php, release 0.4.2.
New features:
- Storage pool / volume related functions (by Lyre)
- VNC client support to get screenshot using gvnccapture (if present)
- experimental - sending keys and client pointer events over VNC protocol
- API to change domain VCPU count, memory amount and guest boot order
- libvirt resources tracking - can be obtained by
libvirt_print_binding_resources() API function
- debug logging using libvirt_logfile_set() API function (default max
log file size can be obtained in PHPInfo output)
- functions to add/remove domain disks/NICs in an easy way (using a
simple PHP API functions)
For this release thanks goes to those guys:
- Lyre <liyong(a)skybility.com> - storage-related functions as well as
many bug fixes
- Yukihiro Kawada <warp.kawada(a)gmail.com> - fix for the memory leak in
libvirt_list_domains()
- Daniel P. Berrange <berrange(a)redhat.com> - bug fixes/improvements
for the build system
- Radek Hladik <r.hladik(a)cybersales.cz> - patch to add API to update
device
- Tiziano Mueller <dev-zero(a)gentoo.org> - several bug fixes for
threaded php and libvirt_connect/version failures without Xen
I hope I didn't forget to mention anybody ;-)
The new release can be found at:
http://libvirt.org/sources/php/libvirt-php-0.4.2.tar.gz
Michal
--
Michal Novotny <minovotn(a)redhat.com>, RHCE, Red Hat
Virtualization Team (xen userspace) | libvirt-php bindings
1
0