[libvirt] [PATCH v3 1/2] network: Refactor code to add bandwidth support for ethernet interfaces
by Anirban Chakraborty
Modified code to set and clear bandwidth cleanly.
Signed-off-by: Anirban Chakraborty <abchak(a)juniper.net>
---
src/conf/domain_conf.h | 7 +++++++
src/lxc/lxc_driver.c | 3 +++
src/lxc/lxc_process.c | 18 +++++++++---------
src/qemu/qemu_command.c | 25 +++++++++++++++++++------
src/qemu/qemu_command.h | 2 ++
src/qemu/qemu_driver.c | 3 +++
src/qemu/qemu_hotplug.c | 12 ++++++++++++
src/qemu/qemu_process.c | 3 +++
src/util/virnetdevmacvlan.c | 10 ----------
src/util/virnetdevmacvlan.h | 1 -
10 files changed, 58 insertions(+), 26 deletions(-)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index afa3da6..f03599e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2848,4 +2848,11 @@ int virDomainObjSetMetadata(virDomainObjPtr vm,
bool virDomainDefNeedsPlacementAdvice(virDomainDefPtr def)
ATTRIBUTE_NONNULL(1);
+static inline bool virNetDevSupportBandwidth(int type)
+{
+ return ((type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ type == VIR_DOMAIN_NET_TYPE_NETWORK ||
+ type == VIR_DOMAIN_NET_TYPE_DIRECT) ? true : false);
+};
+
#endif /* __DOMAIN_CONF_H */
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index b3e506f..a6f1f8a 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -72,6 +72,7 @@
#include "viraccessapicheck.h"
#include "viraccessapichecklxc.h"
#include "virhostdev.h"
+#include "qemu/qemu_command.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -4634,6 +4635,8 @@ lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
detach = vm->def->nets[detachidx];
+ qemuDomainClearNetBandwidth(vm);
+
switch (virDomainNetGetActualType(detach)) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index ed30c37..3192011 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -274,11 +274,6 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn,
if (virNetDevSetOnline(parentVeth, true) < 0)
goto cleanup;
- if (virNetDevBandwidthSet(net->ifname,
- virDomainNetGetActualBandwidth(net),
- false) < 0)
- goto cleanup;
-
if (net->filter &&
virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0)
goto cleanup;
@@ -300,6 +295,7 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,
virNetDevBandwidthPtr bw;
virNetDevVPortProfilePtr prof;
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
+ const char *linkdev = virDomainNetGetActualDirectDev(net);
/* XXX how todo bandwidth controls ?
* Since the 'net-ifname' is about to be moved to a different
@@ -329,14 +325,13 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,
if (virNetDevMacVLanCreateWithVPortProfile(
net->ifname, &net->mac,
- virDomainNetGetActualDirectDev(net),
+ linkdev,
virDomainNetGetActualDirectMode(net),
false, def->uuid,
- virDomainNetGetActualVirtPortProfile(net),
+ prof,
&res_ifname,
VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
- cfg->stateDir,
- virDomainNetGetActualBandwidth(net), 0) < 0)
+ cfg->stateDir, 0) < 0)
goto cleanup;
ret = res_ifname;
@@ -450,6 +445,11 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
goto cleanup;
}
+ /* set network bandwidth */
+ if (virNetDevBandwidthSet(def->nets[i]->ifname,
+ virDomainNetGetActualBandwidth(def->nets[i]), false) < 0)
+ goto cleanup;
+
(*veths)[(*nveths)-1] = veth;
/* Make sure all net definitions will have a name in the container */
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8cb0865..3635712 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -191,7 +191,6 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
virDomainNetGetActualVirtPortProfile(net),
&res_ifname,
vmop, cfg->stateDir,
- virDomainNetGetActualBandwidth(net),
macvlan_create_flags);
if (rc >= 0) {
virDomainAuditNetDevice(def, net, res_ifname, true);
@@ -371,11 +370,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
&net->mac) < 0)
goto cleanup;
- if (virNetDevBandwidthSet(net->ifname,
- virDomainNetGetActualBandwidth(net),
- false) < 0)
- goto cleanup;
-
if (net->filter &&
virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) {
goto cleanup;
@@ -7427,6 +7421,13 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
goto cleanup;
}
+ /* Set Bandwidth */
+ if (virNetDevSupportBandwidth(actualType) &&
+ virNetDevBandwidthSet(net->ifname,
+ virDomainNetGetActualBandwidth(net),
+ false) < 0)
+ goto cleanup;
+
if ((actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
@@ -12452,3 +12453,15 @@ virDomainDefPtr qemuParseCommandLinePid(virCapsPtr qemuCaps,
virStringFreeList(progenv);
return def;
}
+
+void qemuDomainClearNetBandwidth(virDomainObjPtr vm)
+{
+ size_t i;
+ int type;
+
+ for (i = 0; i < vm->def->nnets; i++) {
+ type = virDomainNetGetActualType(vm->def->nets[i]);
+ if (virNetDevSupportBandwidth(type))
+ virNetDevBandwidthClear(vm->def->nets[i]->ifname);
+ }
+}
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index aa40c9e..7963a91 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -277,4 +277,6 @@ int qemuCheckDiskConfig(virDomainDiskDefPtr disk);
bool
qemuCheckFips(void);
+
+void qemuDomainClearNetBandwidth(virDomainObjPtr vm);
#endif /* __QEMU_COMMAND_H__*/
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 4e2b356..1859470 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2196,6 +2196,9 @@ qemuDomainDestroyFlags(virDomainPtr dom,
if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
+ /* Clear network bandwidth */
+ qemuDomainClearNetBandwidth(vm);
+
qemuDomainSetFakeReboot(driver, vm, false);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 1e504ec..f627e69 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -50,6 +50,7 @@
#include "virstring.h"
#include "virtime.h"
#include "storage/storage_driver.h"
+#include "domain_conf.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -948,6 +949,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
goto cleanup;
}
+ /* Set Bandwidth */
+ if (virNetDevSupportBandwidth(actualType) &&
+ virNetDevBandwidthSet(net->ifname,
+ virDomainNetGetActualBandwidth(net), false) < 0)
+ goto cleanup;
+
for (i = 0; i < tapfdSize; i++) {
if (virSecurityManagerSetTapFDLabel(driver->securityManager,
vm->def, tapfd[i]) < 0)
@@ -3516,6 +3523,11 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
}
}
+ if (virNetDevSupportBandwidth(virDomainNetGetActualType(detach)) &&
+ virNetDevBandwidthClear(detach->ifname) < 0)
+ VIR_WARN("cannot clear bandwidth setting for device : %s",
+ detach->ifname);
+
qemuDomainMarkDeviceForRemoval(vm, &detach->info);
qemuDomainObjEnterMonitor(driver, vm);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 95548aa..4d95ec4 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4825,6 +4825,9 @@ void qemuProcessStop(virQEMUDriverPtr driver,
virStrerror(errno, ebuf, sizeof(ebuf)));
}
+ /* Clear network bandwidth */
+ qemuDomainClearNetBandwidth(vm);
+
virDomainConfVMNWFilterTeardown(vm);
if (cfg->macFilter) {
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index c83341c..956a96b 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -811,7 +811,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
char **res_ifname,
virNetDevVPortProfileOp vmOp,
char *stateDir,
- virNetDevBandwidthPtr bandwidth,
unsigned int flags)
{
const char *type = (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
@@ -925,14 +924,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
rc = 0;
}
- if (virNetDevBandwidthSet(cr_ifname, bandwidth, false) < 0) {
- if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP)
- VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
- else
- rc = -1;
- goto disassociate_exit;
- }
-
if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_CREATE ||
vmOp == VIR_NETDEV_VPORT_PROFILE_OP_RESTORE) {
/* Only directly register upon a create or restore (restarting
@@ -1076,7 +1067,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname ATTRIBUTE_UNUSED,
char **res_ifname ATTRIBUTE_UNUSED,
virNetDevVPortProfileOp vmop ATTRIBUTE_UNUSED,
char *stateDir ATTRIBUTE_UNUSED,
- virNetDevBandwidthPtr bandwidth ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(0, -1);
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
index 41aa4e2..f08d32b 100644
--- a/src/util/virnetdevmacvlan.h
+++ b/src/util/virnetdevmacvlan.h
@@ -68,7 +68,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname,
char **res_ifname,
virNetDevVPortProfileOp vmop,
char *stateDir,
- virNetDevBandwidthPtr bandwidth,
unsigned int flags)
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6)
ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(10) ATTRIBUTE_RETURN_CHECK;
--
1.9.1
10 years, 1 month
[libvirt] [PATCH v2] hotplug: Fix libvirtd crash on qemu-attached guest
by John Ferlan
https://bugzilla.redhat.com/show_bug.cgi?id=1141621
The crash in this case was because the qemu-attach code did not create
aliases for qemu cli args. When the detach-interface code was called
it assumed aliases were set resulting in a core when dereferencing the
still NULL alias.
Adding a call to qemuAssignDeviceAliases() resolves the path for
qemu-attach; however, to prevent future issues an additional check
for a NULL value is made and an error provided in the deatch path.
Add some more verbiage to the virsh man page.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
v1 is here:
http://www.redhat.com/archives/libvir-list/2014-September/msg01331.html
Changes since v1:
- Add the call to qemuAssignDeviceAliases() in qemuDomainQemuAttach().
- Move the check for NULL alias inside the CAPS_DEVICE check and emit
an error rather than trying to remove as an "else" condition.
src/qemu/qemu_driver.c | 3 +++
src/qemu/qemu_hotplug.c | 7 +++++++
tools/virsh.pod | 5 +++--
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 117138a..ef4ecd2 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -14746,6 +14746,9 @@ static virDomainPtr qemuDomainQemuAttach(virConnectPtr conn,
if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
goto cleanup;
+ if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
+ goto cleanup;
+
if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
goto cleanup;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index d631887..daebe82 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -3521,6 +3521,13 @@ qemuDomainDetachNetDevice(virConnectPtr conn,
qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
+ if (!detach->info.alias) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("device alias not found: cannot delete the "
+ "net device"));
+ qemuDomainObjExitMonitor(driver, vm);
+ goto cleanup;
+ }
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
qemuDomainObjExitMonitor(driver, vm);
virDomainAuditNet(vm, detach, NULL, "detach", false);
diff --git a/tools/virsh.pod b/tools/virsh.pod
index eae9195..bd17f68 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -3698,8 +3698,9 @@ using the UNIX driver. Ideally the process will also have had the
Not all functions of libvirt are expected to work reliably after
attaching to an externally launched QEMU process. There may be
-issues with the guest ABI changing upon migration, and hotunplug
-may not work.
+issues with the guest ABI changing upon migration and device hotplug
+or hotunplug may not work. The attached environment should be considered
+primarily read-only.
=item B<qemu-monitor-command> I<domain> { [I<--hmp>] | [I<--pretty>] }
I<command>...
--
1.9.3
10 years, 1 month
[libvirt] [PATCH 0/2] Extend NIC_RX_FILTER_CHANGED event handler to process multicast list
by akrowiak@linux.vnet.ibm.com
From: Tony Krowiak <akrowiak(a)linux.vnet.ibm.com>
This patch set extends the handler for qemu's NIC_RX_FILTER_CHANGED event. It adds
code to compare the old and new multicast MAC address lists and programs the
macvtap filters to match the guest.
Tony Krowiak (2):
util: Functions to update host network device's multicast filter
qemu: change macvtap multicast list in response to
NIC_RX_FILTER_CHANGED
10 years, 1 month
[libvirt] [PATCH v3 0/2] network: Add network bandwidth for ethernet type interfaces
by Anirban Chakraborty
V3:
Addressed issues pointed out in V2
Split into two patches
V2:
Addressed comments raised in review of V1.
Consolidate calls to virNetDevBandwidthSet.
Clear bandwidth settings when the interface is detached or domain
destroyed.
V1:
Ethernet interfaces in libvirt currently do not support bandwidth setting.
For example, following xml file for an interface will not apply these
settings to corresponding qdiscs.
Signed-off-by: Anirban Chakraborty <abchak(a)juniper.net>
Anirban Chakraborty (2):
network: Refactor code to add bandwidth support for ethernet interfaces
network: Add code for setting bandwidth for ethernet interfaces
src/conf/domain_conf.h | 8 ++++++++
src/lxc/lxc_driver.c | 3 +++
src/lxc/lxc_process.c | 18 +++++++++---------
src/qemu/qemu_command.c | 25 +++++++++++++++++++------
src/qemu/qemu_command.h | 2 ++
src/qemu/qemu_driver.c | 3 +++
src/qemu/qemu_hotplug.c | 12 ++++++++++++
src/qemu/qemu_process.c | 3 +++
src/util/virnetdevmacvlan.c | 10 ----------
src/util/virnetdevmacvlan.h | 1 -
10 files changed, 59 insertions(+), 26 deletions(-)
--
1.9.1
10 years, 1 month
[libvirt] [PATCH] security_selinux: Don't relabel /dev/net/tun
by Michal Privoznik
https://bugzilla.redhat.com/show_bug.cgi?id=1147057
The code for relabelling the TAP FD is there due to a race. When
libvirt creates a /dev/tapN device it's labeled as
'system_u:object_r:device_t:s0' by default. Later, when
udev/systemd reacts to this device, it's relabelled to the
expected label 'system_u:object_r:tun_tap_device_t:s0'. Hence, we
have a code that relabels the device, to cut the race down. For
more info see ae368ebfcc4.
But the problem is, the relabel function is called on all TUN/TAP
devices. Yes, on /dev/net/tun too. This is however a special kind
of device - other processes uses it too. We shouldn't touch it's
label then.
Ideally, there would an API in SELinux that would label just the
passed FD and not the underlying path. That way, we wouldn't need
to care as we would be not labeling /dev/net/tun but the FD
passed to the domain. Unfortunately, there's no such API so we
have to workaround until then.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/security/security_selinux.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index b7c1015..25e8320 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -2352,7 +2352,7 @@ virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
struct stat buf;
security_context_t fcon = NULL;
virSecurityLabelDefPtr secdef;
- char *str = NULL;
+ char *str = NULL, *proc = NULL, *fd_path = NULL;
int rc = -1;
secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
@@ -2370,6 +2370,23 @@ virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
goto cleanup;
}
+ /* Label /dev/tap.* devices only. Leave /dev/net/tun alone! */
+ if (virAsprintf(&proc, "/proc/self/fd/%d", fd) == -1)
+ goto cleanup;
+
+ if (virFileResolveLink(proc, &fd_path) < 0) {
+ virReportSystemError(errno,
+ _("Unable to resolve link: %s"), proc);
+ goto cleanup;
+ }
+
+ if (!STRPREFIX(fd_path, "/dev/tap")) {
+ VIR_DEBUG("fd=%d points to %s not setting SELinux label",
+ fd, fd_path);
+ rc = 0;
+ goto cleanup;
+ }
+
if (getContext(mgr, "/dev/tap.*", buf.st_mode, &fcon) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot lookup default selinux label for tap fd %d"), fd);
@@ -2384,6 +2401,8 @@ virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
cleanup:
freecon(fcon);
+ VIR_FREE(fd_path);
+ VIR_FREE(proc);
VIR_FREE(str);
return rc;
}
--
2.0.4
10 years, 1 month
[libvirt] [PATCHv2] Introduce virStringStripIPv6Brackets
by Ján Tomko
Helper function to strip the brackets from an IPv6 address.
Tested by viruritest.
---
src/libvirt_private.syms | 1 +
src/util/virstring.c | 22 ++++++++++++++++++++++
src/util/virstring.h | 2 ++
src/util/viruri.c | 20 ++++----------------
tests/virstringtest.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 78 insertions(+), 16 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6265ac..c5397dd 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2004,6 +2004,7 @@ virStringSortCompare;
virStringSortRevCompare;
virStringSplit;
virStringSplitCount;
+virStringStripIPv6Brackets;
virStrncpy;
virStrndup;
virStrToDouble;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 54c0b6f..0cb7f3f 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -929,3 +929,25 @@ virStringReplace(const char *haystack,
return virBufferContentAndReset(&buf);
}
+
+/**
+ * virStringStripIPv6Brackets:
+ * @str: the string to strip
+ *
+ * Modify the string in-place to remove the leading and closing brackets
+ * from an IPv6 address.
+ */
+void
+virStringStripIPv6Brackets(char *str)
+{
+ size_t len;
+
+ if (!str)
+ return;
+
+ len = strlen(str);
+ if (str[0] == '[' && str[len-1] == ']' && strchr(str, ':')) {
+ memmove(&str[0], &str[1], len - 2);
+ str[len - 2] = '\0';
+ }
+}
diff --git a/src/util/virstring.h b/src/util/virstring.h
index b82ef2a..40ebaeb 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -268,4 +268,6 @@ char *virStringReplace(const char *haystack,
const char *newneedle)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+void virStringStripIPv6Brackets(char *str);
+
#endif /* __VIR_STRING_H__ */
diff --git a/src/util/viruri.c b/src/util/viruri.c
index 23d86c5..6166c37 100644
--- a/src/util/viruri.c
+++ b/src/util/viruri.c
@@ -182,22 +182,10 @@ virURIParse(const char *uri)
if (VIR_STRDUP(ret->user, xmluri->user) < 0)
goto error;
- /* First check: does it even make sense to jump inside */
- if (ret->server != NULL &&
- ret->server[0] == '[') {
- size_t length = strlen(ret->server);
-
- /* We want to modify the server string only if there are
- * square brackets on both ends and inside there is IPv6
- * address. Otherwise we could make a mistake by modifying
- * something other than an IPv6 address. */
- if (ret->server[length - 1] == ']' && strchr(ret->server, ':')) {
- memmove(&ret->server[0], &ret->server[1], length - 2);
- ret->server[length - 2] = '\0';
- }
- /* Even after such modification, it is completely ok to free
- * the uri with xmlFreeURI() */
- }
+ /* Strip square bracket from an IPv6 address.
+ * The function modifies the string in-place. Even after such
+ * modification, it is OK to free the URI with xmlFreeURI. */
+ virStringStripIPv6Brackets(ret->server);
if (virURIParseParams(ret) < 0)
goto error;
diff --git a/tests/virstringtest.c b/tests/virstringtest.c
index 10fad2c..841531f 100644
--- a/tests/virstringtest.c
+++ b/tests/virstringtest.c
@@ -522,6 +522,36 @@ testVirStringFreeListCount(const void *opaque ATTRIBUTE_UNUSED)
}
+struct testStripIPv6BracketsData {
+ const char *string;
+ const char *result;
+};
+
+static int testStripIPv6Brackets(const void *args)
+{
+ const struct testStripIPv6BracketsData *data = args;
+ int ret = -1;
+ char *res = NULL;
+
+ if (VIR_STRDUP(res, data->string) < 0)
+ goto cleanup;
+
+ virStringStripIPv6Brackets(res);
+
+ if (STRNEQ_NULLABLE(res, data->result)) {
+ fprintf(stderr, "Returned '%s', expected '%s'\n",
+ NULLSTR(res), NULLSTR(data->result));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(res);
+ return ret;
+}
+
+
static int
mymain(void)
{
@@ -731,6 +761,25 @@ mymain(void)
NULL) < 0)
ret = -1;
+#define TEST_STRIP_IPV6_BRACKETS(str, res) \
+ do { \
+ struct testStripIPv6BracketsData stripData = { \
+ .string = str, \
+ .result = res, \
+ }; \
+ if (virtTestRun("Strip brackets from IPv6 " #str, \
+ testStripIPv6Brackets, &stripData) < 0) \
+ ret = -1; \
+ } while (0)
+
+ TEST_STRIP_IPV6_BRACKETS(NULL, NULL);
+ TEST_STRIP_IPV6_BRACKETS("[]", "[]");
+ TEST_STRIP_IPV6_BRACKETS("[:]", ":");
+ TEST_STRIP_IPV6_BRACKETS("[::1]", "::1");
+ TEST_STRIP_IPV6_BRACKETS("[hello:", "[hello:");
+ TEST_STRIP_IPV6_BRACKETS(":hello]", ":hello]");
+ TEST_STRIP_IPV6_BRACKETS(":[]:", ":[]:");
+
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.0.4
10 years, 1 month
[libvirt] [PATCH v2] qemu: Pass file descriptor when using TPM passthrough
by Stefan Berger
From: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
Pass the TPM file descriptor to QEMU via command line.
Instead of passing /dev/tpm0 we now pass /dev/fdset/10 and the additional
parameters -add-fd set=10,fd=20.
This addresses the use case when QEMU is started with non-root privileges
and QEMU cannot open /dev/tpm0 for example.
One problem is that for the passing of the file descriptor set to work,
virCommandReorderFDs must not be called on the virCommand. This is prevented
by setting a flag in the virCommandPassFDGetFDIndex that is checked to be
clear when virCommandReorderFDs is run.
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 132 ++++++++++++++++++++++++++++++++++++++++++++---
src/util/vircommand.c | 33 ++++++++++++
src/util/vircommand.h | 3 ++
4 files changed, 162 insertions(+), 7 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6265ac..6c697bb 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1158,6 +1158,7 @@ virCommandNewArgList;
virCommandNewArgs;
virCommandNonblockingFDs;
virCommandPassFD;
+virCommandPassFDGetFDIndex;
virCommandPassListenFDs;
virCommandRawStatus;
virCommandRequireHandshake;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8cb0865..2e030fb 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -157,6 +157,58 @@ VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
"interleave");
/**
+ * qemuVirCommandGetFDSet:
+ * @cmd: the command to modify
+ * @fd: fd to reassign to the child
+ *
+ * Get the parameters for the QEMU -add-fd command line option
+ * for the given file descriptor. The file descriptor must previously
+ * have been 'transferred' in a virCommandPassFD() call.
+ * This function for example returns "set=10,fd=20".
+ */
+static char *
+qemuVirCommandGetFDSet(virCommandPtr cmd, int fd)
+{
+ char *result = NULL;
+ int idx = virCommandPassFDGetFDIndex(cmd, fd);
+
+ if (idx >= 0) {
+ ignore_value(virAsprintf(&result, "set=%d,fd=%d", idx, fd) < 0);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("file descriptor %d has not been transferred"), fd);
+ }
+
+ return result;
+}
+
+/**
+ * qemuVirCommandGetDevSet:
+ * @cmd: the command to modify
+ * @fd: fd to reassign to the child
+ *
+ * Get the parameters for the QEMU path= parameter where a file
+ * descriptor is accessed via a file descriptor set, for example
+ * /dev/fdset/10. The file descriptor must previously have been
+ * 'transferred' in a virCommandPassFD() call.
+ */
+static char *
+qemuVirCommandGetDevSet(virCommandPtr cmd, int fd)
+{
+ char *result = NULL;
+ int idx = virCommandPassFDGetFDIndex(cmd, fd);
+
+ if (idx >= 0) {
+ ignore_value(virAsprintf(&result, "/dev/fdset/%d", idx) < 0);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("file descriptor %d has not been transferred"), fd);
+ }
+ return result;
+}
+
+
+/**
* qemuPhysIfaceConnect:
* @def: the definition of the VM (needed by 802.1Qbh and audit)
* @driver: pointer to the driver instance
@@ -5869,14 +5921,20 @@ qemuBuildRNGDeviceArgs(virCommandPtr cmd,
static char *qemuBuildTPMBackendStr(const virDomainDef *def,
+ virCommandPtr cmd,
virQEMUCapsPtr qemuCaps,
- const char *emulator)
+ const char *emulator,
+ int *tpmfd, int *cancelfd)
{
const virDomainTPMDef *tpm = def->tpm;
virBuffer buf = VIR_BUFFER_INITIALIZER;
const char *type = virDomainTPMBackendTypeToString(tpm->type);
- char *cancel_path;
+ char *cancel_path = NULL;
const char *tpmdev;
+ char *devset = NULL, *cancel_devset = NULL;
+
+ *tpmfd = -1;
+ *cancelfd = -1;
virBufferAsprintf(&buf, "%s,id=tpm-%s", type, tpm->info.alias);
@@ -5889,11 +5947,47 @@ static char *qemuBuildTPMBackendStr(const virDomainDef *def,
if (!(cancel_path = virTPMCreateCancelPath(tpmdev)))
goto error;
- virBufferAddLit(&buf, ",path=");
- virBufferEscape(&buf, ',', ",", "%s", tpmdev);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ADD_FD)) {
+ *tpmfd = open(tpmdev, O_RDWR);
+ if (*tpmfd < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not open TPM device %s"), tpmdev);
+ goto error;
+ }
+
+ virCommandPassFD(cmd, *tpmfd,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+ devset = qemuVirCommandGetDevSet(cmd, *tpmfd);
+ if (devset == NULL)
+ goto error;
+
+ *cancelfd = open(cancel_path, O_WRONLY);
+ if (*cancelfd < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not open TPM device's cancel path "
+ "%s"), cancel_path);
+ goto error;
+ }
+
+ virCommandPassFD(cmd, *cancelfd,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+ cancel_devset = qemuVirCommandGetDevSet(cmd, *cancelfd);
+ if (cancel_devset == NULL)
+ goto error;
+
+ virBufferAddLit(&buf, ",path=");
+ virBufferEscape(&buf, ',', ",", "%s", devset);
- virBufferAddLit(&buf, ",cancel-path=");
- virBufferEscape(&buf, ',', ",", "%s", cancel_path);
+ virBufferAddLit(&buf, ",cancel-path=");
+ virBufferEscape(&buf, ',', ",", "%s", cancel_devset);
+ } else {
+ /* all test cases will use this path */
+ virBufferAddLit(&buf, ",path=");
+ virBufferEscape(&buf, ',', ",", "%s", tpmdev);
+
+ virBufferAddLit(&buf, ",cancel-path=");
+ virBufferEscape(&buf, ',', ",", "%s", cancel_path);
+ }
VIR_FREE(cancel_path);
break;
@@ -5913,6 +6007,10 @@ static char *qemuBuildTPMBackendStr(const virDomainDef *def,
emulator, type);
error:
+ VIR_FREE(devset);
+ VIR_FREE(cancel_devset);
+ VIR_FREE(cancel_path);
+
virBufferFreeAndReset(&buf);
return NULL;
}
@@ -9155,13 +9253,33 @@ qemuBuildCommandLine(virConnectPtr conn,
if (def->tpm) {
char *optstr;
+ int tpmfd = -1;
+ int cancelfd = -1;
+ char *fdset;
- if (!(optstr = qemuBuildTPMBackendStr(def, qemuCaps, emulator)))
+ if (!(optstr = qemuBuildTPMBackendStr(def, cmd, qemuCaps, emulator,
+ &tpmfd, &cancelfd)))
goto error;
virCommandAddArgList(cmd, "-tpmdev", optstr, NULL);
VIR_FREE(optstr);
+ if (tpmfd >= 0) {
+ fdset = qemuVirCommandGetFDSet(cmd, tpmfd);
+ if (!fdset)
+ goto error;
+
+ virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
+ }
+
+ if (cancelfd >= 0) {
+ fdset = qemuVirCommandGetFDSet(cmd, cancelfd);
+ if (!fdset)
+ goto error;
+
+ virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
+ }
+
if (!(optstr = qemuBuildTPMDevStr(def, qemuCaps, emulator)))
goto error;
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index cbe94f8..fd70e78 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -67,6 +67,7 @@ enum {
VIR_EXEC_RUN_SYNC = (1 << 3),
VIR_EXEC_ASYNC_IO = (1 << 4),
VIR_EXEC_LISTEN_FDS = (1 << 5),
+ VIR_EXEC_FIXED_FDS = (1 << 6),
};
typedef struct _virCommandFD virCommandFD;
@@ -214,6 +215,12 @@ virCommandReorderFDs(virCommandPtr cmd)
if (!cmd || cmd->has_error || !cmd->npassfd)
return;
+ if ((cmd->flags & VIR_EXEC_FIXED_FDS)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("The fds are fixed and cannot be reordered"));
+ goto error;
+ }
+
for (i = 0; i < cmd->npassfd; i++)
maxfd = MAX(cmd->passfd[i].fd, maxfd);
@@ -1020,6 +1027,32 @@ virCommandPassListenFDs(virCommandPtr cmd)
cmd->flags |= VIR_EXEC_LISTEN_FDS;
}
+/*
+ * virCommandPassFDGetFDIndex:
+ * @cmd: pointer to virCommand
+ * @fd: FD to get index of
+ *
+ * Determine the index of the FD in the transfer set.
+ *
+ * Returns index >= 0 if @set contains @fd,
+ * -1 otherwise.
+ */
+int
+virCommandPassFDGetFDIndex(virCommandPtr cmd, int fd)
+{
+ size_t i = 0;
+
+ while (i < cmd->npassfd) {
+ if (cmd->passfd[i].fd == fd) {
+ cmd->flags |= VIR_EXEC_FIXED_FDS;
+ return i;
+ }
+ i++;
+ }
+
+ return -1;
+}
+
/**
* virCommandSetPidFile:
* @cmd: the command to modify
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index bf65de4..198da2f 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -62,6 +62,9 @@ void virCommandPassFD(virCommandPtr cmd,
void virCommandPassListenFDs(virCommandPtr cmd);
+int virCommandPassFDGetFDIndex(virCommandPtr cmd,
+ int fd);
+
void virCommandSetPidFile(virCommandPtr cmd,
const char *pidfile) ATTRIBUTE_NONNULL(2);
--
1.9.3
10 years, 1 month
[libvirt] [PATCH] Introduce virStringStripIPv6Brackets
by Ján Tomko
Helper function to strip the brackets from an IPv6 address.
Tested by viruritest.
---
src/libvirt_private.syms | 1 +
src/util/virstring.c | 22 ++++++++++++++++++++++
src/util/virstring.h | 2 ++
src/util/viruri.c | 20 ++++----------------
4 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6265ac..c5397dd 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2004,6 +2004,7 @@ virStringSortCompare;
virStringSortRevCompare;
virStringSplit;
virStringSplitCount;
+virStringStripIPv6Brackets;
virStrncpy;
virStrndup;
virStrToDouble;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 54c0b6f..0cb7f3f 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -929,3 +929,25 @@ virStringReplace(const char *haystack,
return virBufferContentAndReset(&buf);
}
+
+/**
+ * virStringStripIPv6Brackets:
+ * @str: the string to strip
+ *
+ * Modify the string in-place to remove the leading and closing brackets
+ * from an IPv6 address.
+ */
+void
+virStringStripIPv6Brackets(char *str)
+{
+ size_t len;
+
+ if (!str)
+ return;
+
+ len = strlen(str);
+ if (str[0] == '[' && str[len-1] == ']' && strchr(str, ':')) {
+ memmove(&str[0], &str[1], len - 2);
+ str[len - 2] = '\0';
+ }
+}
diff --git a/src/util/virstring.h b/src/util/virstring.h
index b82ef2a..40ebaeb 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -268,4 +268,6 @@ char *virStringReplace(const char *haystack,
const char *newneedle)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+void virStringStripIPv6Brackets(char *str);
+
#endif /* __VIR_STRING_H__ */
diff --git a/src/util/viruri.c b/src/util/viruri.c
index 23d86c5..6166c37 100644
--- a/src/util/viruri.c
+++ b/src/util/viruri.c
@@ -182,22 +182,10 @@ virURIParse(const char *uri)
if (VIR_STRDUP(ret->user, xmluri->user) < 0)
goto error;
- /* First check: does it even make sense to jump inside */
- if (ret->server != NULL &&
- ret->server[0] == '[') {
- size_t length = strlen(ret->server);
-
- /* We want to modify the server string only if there are
- * square brackets on both ends and inside there is IPv6
- * address. Otherwise we could make a mistake by modifying
- * something other than an IPv6 address. */
- if (ret->server[length - 1] == ']' && strchr(ret->server, ':')) {
- memmove(&ret->server[0], &ret->server[1], length - 2);
- ret->server[length - 2] = '\0';
- }
- /* Even after such modification, it is completely ok to free
- * the uri with xmlFreeURI() */
- }
+ /* Strip square bracket from an IPv6 address.
+ * The function modifies the string in-place. Even after such
+ * modification, it is OK to free the URI with xmlFreeURI. */
+ virStringStripIPv6Brackets(ret->server);
if (virURIParseParams(ret) < 0)
goto error;
--
2.0.4
10 years, 1 month
[libvirt] Notes: Non-shared storage live migration w/ active blockcommit
by Kashyap Chamarthy
This notes is based on an IRC conversation with Eric Blake, to have
efficient non-shared storage live migration. Thought I'd post my notes
here before I forget. Please review and spot if there are any
inaccuracies.
Procedure
---------
(1) Starting from disk A, create a snapshot A <- A':
$ virsh snapshot-create-as \
--domain f20vm snap1 snap1-desc \
--diskspec hda,file=/export/vmimages/A'.qcow2 \
--disk-only --atomic
(2) Background copy of A to B:
$ virsh blockcopy \
--domain vm1 vda /export/vmimages/B.qcow2 \
--wait --verbose --shallow \
--finish
(3) Create an empty B' with backing file B:
$ qemu-img create -f qcow2 -b B.qcow2 \
-o backing_fmt=qcow2 B'.qcow2
[or]
$ virsh vol-create-as default B'.qcow2 1G \
--format qcow2 \
--backing-vol B.qcow2 --backing-vol-format qcow2
(4) Do a shallow blockcopy of A' to B':
$ virsh blockcopy \
--domain vm1 vda /export/vmimages/B'.qcow2 \
--wait --verbose --shallow \
--finish
(5) Then live shallow commit of B:
$ virsh blockcommit \
--domain f20vm vda \
--wait --verbose --shallow \
--pivot --active --finish
Block Commit: [100 %]
Successfully pivoted
--
/kashyap
10 years, 1 month
[libvirt] Features - virDomainOpenConsole
by Andre Smith
Hi,
We urgently need proper virDomainOpenConsole support for both VMware and
Virtualbox. Since this is for our own commercial usage, my employer has
authorized me to find a developer that can do the work quickly and properly
and to pay them for their efforts.
Please contact me directly at this email address if you are both interested
and able.
thank you.
10 years, 1 month