[libvirt] [RFC PATCH V2] Add proxy FS support to libvirt
by M. Mohan Kumar
From: "M. Mohan Kumar" <mohan(a)in.ibm.com>
A new FS driver type 'proxy' is added to QEMU 9p server. This patch adds
support for using proxy FS driver from libvirt.
QEMU proxy FS driver uses socket for communicating between helper and qemu
proxy FS driver. Proxy helper (a stand alone binary part of qemu) is invoked
with one of the descriptors created using socketpair call and the share path.
Similarly QEMU is invoked with another descriptor created using the same
socketpair system call and with other required FS driver parameters.
Need for proxy FS driver
========================
Pass through security model in QEMU 9p server has following issues:
1) TOCTTOU vulnerability: Following symbolic links in the server could
provide access to files beyond 9p export path.
2) Running QEMU with root privilege could be a security issue (pass
through security model needs root privilege).
Proxy FS driver is implemented to solve these issues.
Proxy FS uses chroot + socket combination for securing the vulnerability
known with following symbolic links. Intention of adding a new filesystem
type is to allow qemu to run in non-root mode, but doing privileged
operations in a chroot environment using socket IO.
Proxy helper is invoked with root privileges and chroots into 9p export path.
QEMU proxy fs driver sends filesystem request to proxy helper and receives the
response from it.
Proxy helper is designed such a way that it needs only few capabilities related
to filesystem operations (such as CAP_DAC_OVERRIDE, CAP_FOWNER, etc) and all
other capabilities are dropped (CAP_SYS_CHROOT, etc)
Proxy patches
http://permalink.gmane.org/gmane.comp.emulators.qemu/128735
Signed-off-by: M. Mohan Kumar <mohan(a)in.ibm.com>
---
Changes from previous version
* Remove the xml node for specifying the virtfs-proxy-helper, now it is
determined from qemu binary.
docs/formatdomain.html.in | 3 +-
src/conf/domain_conf.c | 3 +-
src/conf/domain_conf.h | 2 +-
src/qemu/qemu_capabilities.c | 3 ++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 71 ++++++++++++++++++++++++++++++++++++++++--
src/qemu/qemu_command.h | 3 +-
tests/qemuhelptest.c | 3 +-
8 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 18b7e22..e398779 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1336,7 +1336,8 @@
This mode also has an optional
sub-element <code>driver</code>, with an
attribute <code>type='path'</code>
- or <code>type='handle'</code> <span class="since">(since
+ or <code>type='handle'</code>
+ or <code>type='proxy'</code> <span class="since">(since
0.9.7)</span>.
</dd>
<dt><code>type='template'</code></dt>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0190a81..2d45324 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -250,7 +250,8 @@ VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
VIR_ENUM_IMPL(virDomainFSDriverType, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
"default",
"path",
- "handle")
+ "handle",
+ "proxy")
VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
"passthrough",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 03aa5b6..3796da4 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -466,6 +466,7 @@ enum virDomainFSDriverType {
VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT = 0,
VIR_DOMAIN_FS_DRIVER_TYPE_PATH,
VIR_DOMAIN_FS_DRIVER_TYPE_HANDLE,
+ VIR_DOMAIN_FS_DRIVER_TYPE_PROXY,
VIR_DOMAIN_FS_DRIVER_TYPE_LAST
};
@@ -491,7 +492,6 @@ struct _virDomainFSDef {
virDomainDeviceInfo info;
};
-
/* 5 different types of networking config */
enum virDomainNetType {
VIR_DOMAIN_NET_TYPE_USER,
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 43c7578..9c01a3b 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -144,6 +144,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"ich9-ahci",
"no-acpi",
"fsdev-readonly",
+ "fsdev-proxy",
);
struct qemu_feature_flags {
@@ -1083,6 +1084,8 @@ qemuCapsComputeCmdFlags(const char *help,
qemuCapsSet(flags, QEMU_CAPS_FSDEV);
if (strstr(fsdev, "readonly"))
qemuCapsSet(flags, QEMU_CAPS_FSDEV_READONLY);
+ if (strstr(fsdev, "sock_fd"))
+ qemuCapsSet(flags, QEMU_CAPS_FSDEV_PROXY);
}
if (strstr(help, "-smbios type"))
qemuCapsSet(flags, QEMU_CAPS_SMBIOS_TYPE);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index c759baf..e129e35 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -117,6 +117,7 @@ enum qemuCapsFlags {
QEMU_CAPS_ICH9_AHCI = 77, /* -device ich9-ahci */
QEMU_CAPS_NO_ACPI = 78, /* -no-acpi */
QEMU_CAPS_FSDEV_READONLY =79, /* -fsdev readonly supported */
+ QEMU_CAPS_FSDEV_PROXY = 80, /* -fsdev proxy supported */
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 f2e9cfa..0c79340 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -44,6 +44,7 @@
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <libgen.h>
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -106,7 +107,8 @@ VIR_ENUM_DECL(qemuDomainFSDriver)
VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
"local",
"local",
- "handle");
+ "handle",
+ "proxy");
static void
@@ -2080,9 +2082,43 @@ error:
return NULL;
}
+/*
+ * Invokes the Proxy Helper with one of the socketpair as its parameter
+ *
+ */
+static int qemuInvokeProxyHelper(const char *emulator, int sock, const char *path)
+{
+#define HELPER "virtfs-proxy-helper"
+ int ret_val, status;
+ virCommandPtr cmd;
+ char *helper, *dname;
+
+ dname = dirname(strdup(emulator));
+ if (virAsprintf(&helper, "%s/%s", dname, HELPER) < 0) {
+ VIR_FREE(dname);
+ virReportOOMError();
+ return -1;
+ }
+
+ cmd = virCommandNewArgList(helper, NULL);
+ virCommandAddArg(cmd, "-f");
+ virCommandAddArgFormat(cmd, "%d", sock);
+ virCommandAddArg(cmd, "-p");
+ virCommandAddArgFormat(cmd, "%s", path);
+ virCommandTransferFD(cmd, sock);
+ virCommandDaemonize(cmd);
+ ret_val = virCommandRun(cmd, &status);
+ if (ret_val < 0)
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("%s can't execute"), helper);
+ virCommandFree(cmd);
+ VIR_FREE(helper);
+ VIR_FREE(dname);
+ return ret_val;
+}
char *qemuBuildFSStr(virDomainFSDefPtr fs,
- virBitmapPtr qemuCaps ATTRIBUTE_UNUSED)
+ virBitmapPtr qemuCaps ATTRIBUTE_UNUSED, int qemuSocket)
{
virBuffer opt = VIR_BUFFER_INITIALIZER;
const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver);
@@ -2108,6 +2144,10 @@ char *qemuBuildFSStr(virDomainFSDefPtr fs,
virBufferAddLit(&opt, ",security_model=none");
}
virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
+
+ if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PROXY)
+ virBufferAsprintf(&opt, ",sock_fd=%d", qemuSocket);
+
virBufferAsprintf(&opt, ",path=%s", fs->src);
if (fs->readonly) {
@@ -4426,10 +4466,35 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV)) {
for (i = 0 ; i < def->nfss ; i++) {
char *optstr;
+ int sockets[2] = {-1, -1};
virDomainFSDefPtr fs = def->fss[i];
+ /*
+ * If its a proxy FS, we need to create a socket pair
+ * and invoke proxy_helper
+ */
+ if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PROXY) {
+ if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV_PROXY) < 0) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("proxy helper not supported"));
+ goto error;
+ }
+ /* create a socket pair */
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("socketpair failed"));
+ goto error;
+ }
+ virCommandTransferFD(cmd, sockets[1]);
+ if (qemuInvokeProxyHelper(def->emulator, sockets[0],
+ fs->src) < 0) {
+ VIR_FORCE_CLOSE(sockets[0]);
+ VIR_FORCE_CLOSE(sockets[1]);
+ goto error;
+ }
+ }
virCommandAddArg(cmd, "-fsdev");
- if (!(optstr = qemuBuildFSStr(fs, qemuCaps)))
+ if (!(optstr = qemuBuildFSStr(fs, qemuCaps, sockets[1])))
goto error;
virCommandAddArg(cmd, optstr);
VIR_FREE(optstr);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index de61cf3..8e4f335 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -87,7 +87,8 @@ char *qemuBuildDriveStr(virConnectPtr conn,
bool bootable,
virBitmapPtr qemuCaps);
char *qemuBuildFSStr(virDomainFSDefPtr fs,
- virBitmapPtr qemuCaps);
+ virBitmapPtr qemuCaps,
+ int qemuSocket);
/* Current, best practice */
char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 60155e7..455a7e1 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -648,7 +648,8 @@ mymain(void)
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_NO_ACPI,
- QEMU_CAPS_FSDEV_READONLY);
+ QEMU_CAPS_FSDEV_READONLY,
+ QEMU_CAPS_FSDEV_PROXY);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.7.6
12 years, 9 months
[libvirt] [PATCH] maint: Add test output files to .gitignore
by Peter Krempa
Commit 8f00276c8a6140cec6a6d50441c802981d329c0c consolidated other
.gitignore files to the master one, but forgot to add some test output
files.
---
Detected by git status on a cleaned repo with make check done:
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# tests/commandtest
# tests/virtimetest
.gitignore | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3e85e4d..b7561dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -111,6 +111,7 @@
/tests/*.pid
/tests/*xml2*test
/tests/commandhelper
+/tests/commandtest
/tests/conftest
/tests/cputest
/tests/domainsnapshotxml2xmltest
@@ -142,6 +143,7 @@
/tests/virhashtest
/tests/virnet*test
/tests/virshtest
+/tests/virtimetest
/tests/vmx2xmltest
/tests/xencapstest
/tests/xmconfigtest
--
1.7.3.4
12 years, 9 months
[libvirt] [PATCH] Update myself in AUTHORS
by ajia@redhat.com
From: Alex Jia <ajia(a)redhat.com>
Move myself from 'Previous maintainers' section to 'the primary maintainers and
people with commit access rights' section, because I have a commit right now.
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
AUTHORS | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index ee510ab..578a377 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -30,6 +30,7 @@ The primary maintainers and people with commit access rights:
Michal Prívozník <mprivozn(a)redhat.com>
Peter Krempa <pkrempa(a)redhat.com>
Christophe Fergeau <cfergeau(a)redhat.com>
+ Alex Jia <ajia(a)redhat.com>
Previous maintainers:
Karel Zak <kzak(a)redhat.com>
@@ -182,7 +183,6 @@ Patches have also been contributed by:
Guannan Ren <gren(a)redhat.com>
John Williams <john.williams(a)petalogix.com>
Michael Santos <michael.santos(a)gmail.com>
- Alex Jia <ajia(a)redhat.com>
Oskari Saarenmaa <os(a)ohmu.fi>
Nan Zhang <nzhang(a)redhat.com>
Wieland Hoffmann <themineo(a)googlemail.com>
--
1.7.1
12 years, 9 months
[libvirt] Are they reasonable FD leaks?
by Alex Jia
Hi all,
I met some FD leaks when I tried the following scenario:
% dd if=/dev/null of=/var/lib/libvirt/images/foo bs=1 count=1 seek=10M
% virsh define foo.xml (disk source file points to '/var/lib/libvirt/images/foo')
% virsh vol-clone foo foo-clone default (the original guest name is 'foo')
% virsh pool-refresh default
% virsh vol-list default (make sure 'foo-clone' volume exists)
% virsh define foo-clone.xml (disk source file points to '/var/lib/libvirt/images/foo-clone')
% valgrind -v --track-fds=yes virsh undefine foo-clone --remove-all-storage
<snip>
==21003== FILE DESCRIPTORS: 10 open at exit.
==21003== Open file descriptor 9:
==21003== at 0x39CF0D8BB7: pipe2 (in /lib64/libc-2.12.so)
==21003== by 0x4E4FC97: rpl_pipe2 (pipe2.c:59)
==21003== by 0x4D5C3FA: virNetClientNew (virnetclient.c:278)
==21003== by 0x4D5C7B2: virNetClientNewUNIX (virnetclient.c:352)
==21003== by 0x4D47EAA: doRemoteOpen (remote_driver.c:601)
==21003== by 0x4D499AF: remoteOpen (remote_driver.c:873)
==21003== by 0x4D12D23: do_open (libvirt.c:1196)
==21003== by 0x4D13EE5: virConnectOpenAuth (libvirt.c:1422)
==21003== by 0x415040: vshReconnect (virsh.c:637)
==21003== by 0x4152A7: vshCommandRun (virsh.c:17688)
==21003== by 0x4264D3: main (virsh.c:19270)
==21003==
==21003== Open file descriptor 8:
==21003== at 0x39CF0D8BB7: pipe2 (in /lib64/libc-2.12.so)
==21003== by 0x4E4FC97: rpl_pipe2 (pipe2.c:59)
==21003== by 0x4D5C3FA: virNetClientNew (virnetclient.c:278)
==21003== by 0x4D5C7B2: virNetClientNewUNIX (virnetclient.c:352)
==21003== by 0x4D47EAA: doRemoteOpen (remote_driver.c:601)
==21003== by 0x4D499AF: remoteOpen (remote_driver.c:873)
==21003== by 0x4D12D23: do_open (libvirt.c:1196)
==21003== by 0x4D13EE5: virConnectOpenAuth (libvirt.c:1422)
==21003== by 0x415040: vshReconnect (virsh.c:637)
==21003== by 0x4152A7: vshCommandRun (virsh.c:17688)
==21003== by 0x4264D3: main (virsh.c:19270)
==21003==
==21003== Open AF_UNIX socket 7: <unknown>
==21003== at 0x39CF0E67B7: socket (in /lib64/libc-2.12.so)
==21003== by 0x4D6B0F0: virNetSocketNewConnectUNIX (virnetsocket.c:490)
==21003== by 0x4D5C79F: virNetClientNewUNIX (virnetclient.c:349)
==21003== by 0x4D47EAA: doRemoteOpen (remote_driver.c:601)
==21003== by 0x4D499AF: remoteOpen (remote_driver.c:873)
==21003== by 0x4D12D23: do_open (libvirt.c:1196)
==21003== by 0x4D13EE5: virConnectOpenAuth (libvirt.c:1422)
==21003== by 0x415040: vshReconnect (virsh.c:637)
==21003== by 0x4152A7: vshCommandRun (virsh.c:17688)
==21003== by 0x4264D3: main (virsh.c:19270)
</snip>
It seems libvirt deliberately leaks these FDs, right?
Regards,
Alex
12 years, 9 months
[libvirt] [PATCH] virsh: Fix resource leak while listing inactive domains with titles
by Peter Krempa
Commit fad5cd210899dfde4afe36712754dc921c3f3051 introduces a new flag
that allows to show domain's title with domains. This commit introduced
resource leak while listing inactive domains with titles.
---
Sadly, I missed this even when it was incorrectly intended. :(
(extra context for easier review)
tools/virsh.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 1613d2e..d6fe680 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -1000,34 +1000,34 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
if (desc) {
if (!(title = vshGetDomainDescription(ctl, dom, true, 0)))
goto cleanup;
vshPrint(ctl, "%-5s %-30s %-10s %s\n",
"-",
names[i],
state == -2 ? _("saved") : _(vshDomainStateToString(state)),
title);
VIR_FREE(title);
} else {
vshPrint(ctl, " %-5s %-30s %s\n",
"-",
names[i],
state == -2 ? _("saved") : _(vshDomainStateToString(state)));
+ }
virDomainFree(dom);
VIR_FREE(names[i]);
- }
}
ret = true;
cleanup:
VIR_FREE(ids);
VIR_FREE(names);
return ret;
}
/*
* "desc" command for managing domain description and title
*/
static const vshCmdInfo info_desc[] = {
{"help", N_("show or set domain's description or title")},
{"desc", N_("Allows to show or modify description or title of a domain.")},
--
1.7.3.4
12 years, 9 months
[libvirt] [libvirt-glib 1/7] Fix gvir_config_object_new_from_xml error reporting
by Christophe Fergeau
It's currently failing to report parsing errors if the passed in
error is NULL.
---
libvirt-gconfig/libvirt-gconfig-object.c | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/libvirt-gconfig/libvirt-gconfig-object.c b/libvirt-gconfig/libvirt-gconfig-object.c
index 2e28208..7e3cb88 100644
--- a/libvirt-gconfig/libvirt-gconfig-object.c
+++ b/libvirt-gconfig/libvirt-gconfig-object.c
@@ -636,10 +636,13 @@ GVirConfigObject *gvir_config_object_new_from_xml(GType type,
GVirConfigObject *object;
GVirConfigXmlDoc *doc;
xmlNodePtr node;
+ GError *tmp_error = NULL;
- node = gvir_config_xml_parse(xml, root_name, error);
- if ((error != NULL) && (*error != NULL))
+ node = gvir_config_xml_parse(xml, root_name, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error(error, tmp_error);
return NULL;
+ }
doc = gvir_config_xml_doc_new(node->doc);
object = GVIR_CONFIG_OBJECT(g_object_new(type,
"doc", doc,
--
1.7.7.6
12 years, 9 months
[libvirt] [PATCH] xen_xm: Fix SIGSEGV in xenXMDomainDefineXML
by Philipp Hahn
On CentOS5 with xen-3.0.3:
Program received signal SIGSEGV, Segmentation fault.
virFree (ptrptr=0x8) at util/memory.c:310
310 free(*(void**)ptrptr);
(gdb) bt
#0 virFree (ptrptr=0x8) at util/memory.c:310
#1 0x00002aaaaae167c8 in xenXMDomainDefineXML (conn=0x694e80, xml=0x6b2ce0 "P\fk") at xen/xm_internal.c:1199
#2 0x00002aaaaae070d7 in xenUnifiedDomainDefineXML (conn=0x8,
xml=0x6ac040 "<domain type='xen'>\n <name>pv</name>\n <uuid>20291bc0-453a-4d6c-c6ac-4e5af63b932c</uuid>\n <memory>1048576</memory>\n <currentMemory>1048576</currentMemory>\n <vcpu>1</vcpu>\n <os>\n <type arch='x8"...) at xen/xen_driver.c:1524
#3 0x00002aaaaada7803 in virDomainDefineXML (conn=0x694e80,
xml=0x6ac040 "<domain type='xen'>\n <name>pv</name>\n <uuid>20291bc0-453a-4d6c-c6ac-4e5af63b932c</uuid>\n <memory>1048576</memory>\n <currentMemory>1048576</currentMemory>\n <vcpu>1</vcpu>\n <os>\n <type arch='x8"...) at libvirt.c:7823
#4 0x0000000000426173 in cmdEdit (ctl=0x7fffffffb8e0, cmd=<value optimized out>) at virsh.c:14882
#5 0x000000000041c9ce in vshCommandRun (ctl=0x7fffffffb8e0, cmd=0x658c50) at virsh.c:17712
#6 0x000000000042c3b9 in main (argc=1, argv=<value optimized out>) at virsh.c:19317
Signed-off-by: Philipp Hahn <hahn(a)univention.de>
---
src/xen/xm_internal.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index a34e906..02a0e1d 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -1196,7 +1196,8 @@ virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml)
error:
VIR_FREE(filename);
- VIR_FREE(entry->filename);
+ if (entry)
+ VIR_FREE(entry->filename);
VIR_FREE(entry);
virDomainDefFree(def);
xenUnifiedUnlock(priv);
--
1.7.1
12 years, 9 months
[libvirt] [libvirt-glib] Don't assign const char * to non-const
by Christophe Fergeau
This causes a gcc warning.
---
libvirt-gobject/libvirt-gobject-storage-pool.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-storage-pool.c b/libvirt-gobject/libvirt-gobject-storage-pool.c
index db496f3..5a4b4bc 100644
--- a/libvirt-gobject/libvirt-gobject-storage-pool.c
+++ b/libvirt-gobject/libvirt-gobject-storage-pool.c
@@ -548,7 +548,7 @@ GVirStorageVol *gvir_storage_pool_create_volume
}
GVirStorageVol *volume;
- char *name;
+ const char *name;
volume = GVIR_STORAGE_VOL(g_object_new(GVIR_TYPE_STORAGE_VOL,
"handle", handle,
--
1.7.7.6
12 years, 9 months
[libvirt] [PATCH] RFC Libvirt + Openvswitch
by Ansis Atteka
This patch allows libvirt to add interfaces to already
existing Open vSwitch bridges. The following syntax in
domain XML file must be used:
<interface type='bridge'>
<mac address='52:54:00:d0:3f:f2'/>
<source bridge='ovsbr'/>
<virtualport type='openvswitch'>
<parameters interfaceid='921a80cd-e6de-5a2e-db9c-ab27f15a6e1d'/>
</virtualport>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
or if libvirt should auto-generate the interfaceid us following syntax:
<interface type='bridge'>
<mac address='52:54:00:d0:3f:f2'/>
<source bridge='ovsbr'/>
<virtualport type='openvswitch'>
</virtualport>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
To create Open vSwitch bridge us following command:
ovs-vsctl add-br ovsbr
1. This patch has been tested only on Ubuntu 11.10 with KVM
2. Auto-generated interfaceid is not persistent across libvirt reboots
---
configure.ac | 5 ++
src/Makefile.am | 2 +
src/conf/domain_conf.c | 46 ++++++++++++++
src/conf/domain_conf.h | 6 ++
src/conf/netdev_openvswitch_conf.c | 94 +++++++++++++++++++++++++++++
src/conf/netdev_openvswitch_conf.h | 39 ++++++++++++
src/libvirt_private.syms | 12 ++++
src/lxc/lxc_driver.c | 19 ++++--
src/network/bridge_driver.c | 3 +-
src/qemu/qemu_command.c | 3 +-
src/qemu/qemu_hotplug.c | 7 ++-
src/qemu/qemu_process.c | 3 +
src/uml/uml_conf.c | 3 +-
src/util/uuid.c | 19 ++++++
src/util/uuid.h | 1 +
src/util/virnetdevopenvswitch.c | 114 ++++++++++++++++++++++++++++++++++++
src/util/virnetdevopenvswitch.h | 46 ++++++++++++++
src/util/virnetdevtap.c | 32 +++++++++-
src/util/virnetdevtap.h | 8 ++-
19 files changed, 447 insertions(+), 15 deletions(-)
create mode 100644 src/conf/netdev_openvswitch_conf.c
create mode 100644 src/conf/netdev_openvswitch_conf.h
create mode 100644 src/util/virnetdevopenvswitch.c
create mode 100644 src/util/virnetdevopenvswitch.h
diff --git a/configure.ac b/configure.ac
index 9fb7bfc..dca178f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -213,6 +213,8 @@ AC_PATH_PROG([UDEVSETTLE], [udevsettle], [],
[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
AC_PATH_PROG([MODPROBE], [modprobe], [],
[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
+AC_PATH_PROG([OVSVSCTL], [ovs-vsctl], [ovs-vsctl],
+ [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
AC_DEFINE_UNQUOTED([DNSMASQ],["$DNSMASQ"],
[Location or name of the dnsmasq program])
@@ -220,6 +222,9 @@ AC_DEFINE_UNQUOTED([RADVD],["$RADVD"],
[Location or name of the radvd program])
AC_DEFINE_UNQUOTED([TC],["$TC"],
[Location or name of the tc profram (see iproute2)])
+AC_DEFINE_UNQUOTED([OVSVSCTL],["$OVSVSCTL"],
+ [Location or name of the ovs-vsctl program])
+
if test -n "$UDEVADM"; then
AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"],
[Location or name of the udevadm program])
diff --git a/src/Makefile.am b/src/Makefile.am
index a3dd847..79a2dde 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ UTIL_SOURCES = \
util/virmacaddr.h util/virmacaddr.c \
util/virnetdev.h util/virnetdev.c \
util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
+ util/virnetdevopenvswitch.h util/virnetdevopenvswitch.c \
util/virnetdevbridge.h util/virnetdevbridge.c \
util/virnetdevmacvlan.c util/virnetdevmacvlan.h \
util/virnetdevtap.h util/virnetdevtap.c \
@@ -136,6 +137,7 @@ LOCK_DRIVER_SANLOCK_SOURCES = \
NETDEV_CONF_SOURCES = \
conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
+ conf/netdev_openvswitch_conf.h conf/netdev_openvswitch_conf.c \
conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_conf.c
# XML configuration format handling sources
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index aa4b32d..abec371 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -31,6 +31,7 @@
#include <sys/time.h>
#include <strings.h>
+#include "internal.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "domain_conf.h"
@@ -50,6 +51,7 @@
#include "count-one-bits.h"
#include "secret_conf.h"
#include "netdev_vport_profile_conf.h"
+#include "netdev_openvswitch_conf.h"
#include "netdev_bandwidth_conf.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -952,6 +954,7 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
VIR_FREE(def->data.bridge.brname);
+ VIR_FREE(def->data.bridge.ovsPort);
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
VIR_FREE(def->data.direct.linkdev);
@@ -995,6 +998,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
case VIR_DOMAIN_NET_TYPE_BRIDGE:
VIR_FREE(def->data.bridge.brname);
VIR_FREE(def->data.bridge.ipaddr);
+ VIR_FREE(def->data.bridge.ovsPort);
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
@@ -3737,7 +3741,15 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
}
if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt);
actual->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", ctxt);
+ if (virtPortNode && virXMLPropString(virtPortNode, "type") &&
+ STREQ(virXMLPropString(virtPortNode, "type"), "openvswitch")) {
+ if (!(actual->data.bridge.ovsPort =
+ virNetDevOpenvswitchPortParse(virtPortNode))) {
+ goto error;
+ }
+ }
} else if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
xmlNodePtr virtPortNode;
@@ -3817,6 +3829,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *linkstate = NULL;
virNWFilterHashTablePtr filterparams = NULL;
virNetDevVPortProfilePtr virtPort = NULL;
+ virNetDevOpenvswitchPortPtr ovsPort = NULL;
virDomainActualNetDefPtr actual = NULL;
xmlNodePtr oldnode = ctxt->node;
int ret;
@@ -3870,6 +3883,13 @@ virDomainNetDefParseXML(virCapsPtr caps,
xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
if (!(virtPort = virNetDevVPortProfileParse(cur)))
goto error;
+ } else if ((ovsPort == NULL) &&
+ ((def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
+ xmlStrEqual(cur->name, BAD_CAST "virtualport") &&
+ virXMLPropString(cur, "type") &&
+ STREQ(virXMLPropString(cur, "type"), "openvswitch"))) {
+ if (!(ovsPort = virNetDevOpenvswitchPortParse(cur)))
+ goto error;
} else if ((network == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -4005,6 +4025,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
def->data.bridge.ipaddr = address;
address = NULL;
}
+ def->data.bridge.ovsPort = ovsPort;
+ ovsPort = NULL;
break;
case VIR_DOMAIN_NET_TYPE_CLIENT:
@@ -10427,6 +10449,12 @@ virDomainActualNetDefFormat(virBufferPtr buf,
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferEscapeString(buf, " <source bridge='%s'/>\n",
def->data.bridge.brname);
+ if (def->data.bridge.ovsPort) {
+ virBufferAdjustIndent(buf, 6);
+ if (virNetDevOpenvswitchPortFormat(def->data.bridge.ovsPort, buf) < 0)
+ return -1;
+ virBufferAdjustIndent(buf, -6);
+ }
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
@@ -10514,6 +10542,12 @@ virDomainNetDefFormat(virBufferPtr buf,
if (def->data.bridge.ipaddr)
virBufferAsprintf(buf, " <ip address='%s'/>\n",
def->data.bridge.ipaddr);
+ if (def->data.bridge.ovsPort) {
+ virBufferAdjustIndent(buf, 6);
+ if (virNetDevOpenvswitchPortFormat(def->data.bridge.ovsPort, buf) < 0)
+ return -1;
+ virBufferAdjustIndent(buf, -6);
+ }
break;
case VIR_DOMAIN_NET_TYPE_SERVER:
@@ -13851,6 +13885,18 @@ virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
return iface->bandwidth;
}
+virNetDevOpenvswitchPortPtr
+virDomainNetGetActualOpenvswitchPortPtr(virDomainNetDefPtr iface)
+{
+ if (iface->type != VIR_DOMAIN_NET_TYPE_BRIDGE)
+ return NULL;
+ if (iface->data.bridge.ovsPort)
+ return iface->data.bridge.ovsPort;
+ if (!iface->data.network.actual)
+ return NULL;
+ return iface->data.network.actual->data.bridge.ovsPort;
+}
+
/* Return listens[ii] from the appropriate union for the graphics
* type, or NULL if this is an unsuitable type, or the index is out of
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 0a2795d..b7eb7d1 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -41,6 +41,7 @@
# include "virnetdevmacvlan.h"
# include "sysinfo.h"
# include "virnetdevvportprofile.h"
+# include "virnetdevopenvswitch.h"
# include "virnetdevbandwidth.h"
/* Different types of hypervisor */
@@ -594,6 +595,7 @@ struct _virDomainActualNetDef {
union {
struct {
char *brname;
+ virNetDevOpenvswitchPortPtr ovsPort;
} bridge;
struct {
char *linkdev;
@@ -645,6 +647,7 @@ struct _virDomainNetDef {
struct {
char *brname;
char *ipaddr;
+ virNetDevOpenvswitchPortPtr ovsPort;
} bridge;
struct {
char *name;
@@ -1877,6 +1880,9 @@ virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface);
virNetDevBandwidthPtr
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface);
+virNetDevOpenvswitchPortPtr
+virDomainNetGetActualOpenvswitchPortPtr(virDomainNetDefPtr iface);
+
int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller);
void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
diff --git a/src/conf/netdev_openvswitch_conf.c b/src/conf/netdev_openvswitch_conf.c
new file mode 100644
index 0000000..ddae3aa
--- /dev/null
+++ b/src/conf/netdev_openvswitch_conf.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * 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:
+ * Dan Wendlandt <dan(a)nicira.com>
+ * Kyle Mestery <kmestery(a)cisco.com>
+ * Ansis Atteka <aatteka(a)nicira.com>
+ */
+
+#include <config.h>
+
+#include "netdev_openvswitch_conf.h"
+#include "virterror_internal.h"
+#include "memory.h"
+#include "uuid.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+#define virNetDevError(code, ...) \
+ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+
+virNetDevOpenvswitchPortPtr
+virNetDevOpenvswitchPortParse(xmlNodePtr node)
+{
+ char *InterfaceID = NULL;
+ virNetDevOpenvswitchPortPtr ovsPort = NULL;
+ xmlNodePtr cur = node->children;
+
+ if (VIR_ALLOC(ovsPort) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {
+ InterfaceID = virXMLPropString(cur, "interfaceid");
+ break;
+ }
+ cur = cur->next;
+ }
+
+ if (InterfaceID == NULL || (strlen(InterfaceID) == 0)) {
+ // interfaceID does not have to be a UUID,
+ // but a UUID is a reasonable default
+ if (virUUIDGenerateStr(ovsPort->InterfaceID)) {
+ virNetDevError(VIR_ERR_XML_ERROR, "%s",
+ _("cannot generate a random uuid for interfaceid"));
+ goto error;
+ }
+ } else {
+ if (virStrcpyStatic(ovsPort->InterfaceID, InterfaceID) == NULL) {
+ virNetDevError(VIR_ERR_XML_ERROR, "%s",
+ _("InterfaceID parameter too long"));
+ goto error;
+ }
+ }
+
+cleanup:
+ return ovsPort;
+
+error:
+ VIR_FREE(ovsPort);
+ goto cleanup;
+}
+
+
+int
+virNetDevOpenvswitchPortFormat(virNetDevOpenvswitchPortPtr ovsPort,
+ virBufferPtr buf)
+{
+ if (ovsPort == NULL)
+ return 0;
+
+ virBufferAsprintf(buf, "<virtualport type='openvswitch'>\n");
+ virBufferAsprintf(buf, " <parameters interfaceid='%s'/>\n",
+ ovsPort->InterfaceID);
+ virBufferAddLit(buf, "</virtualport>\n");
+ return 0;
+}
diff --git a/src/conf/netdev_openvswitch_conf.h b/src/conf/netdev_openvswitch_conf.h
new file mode 100644
index 0000000..fd8e079
--- /dev/null
+++ b/src/conf/netdev_openvswitch_conf.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * 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:
+ * Dan Wendlandt <dan(a)nicira.com>
+ * Kyle Mestery <kmestery(a)cisco.com>
+ * Ansis Atteka <aatteka(a)nicira.com>
+ */
+
+#ifndef __VIR_NETDEV_OPENVSWITCH_CONF_H__
+# define __VIR_NETDEV_OPENVSWITCH_CONF_H__
+
+# include "internal.h"
+# include "virnetdevopenvswitch.h"
+# include "buf.h"
+# include "xml.h"
+
+virNetDevOpenvswitchPortPtr
+virNetDevOpenvswitchPortParse(xmlNodePtr node);
+
+int
+virNetDevOpenvswitchPortFormat(virNetDevOpenvswitchPortPtr ovsPort,
+ virBufferPtr buf);
+
+#endif /* __VIR_NETDEV_OPENVSWITCH_CONF_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6ad36c..0666d5c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -379,6 +379,7 @@ virDomainNetGetActualBridgeName;
virDomainNetGetActualDirectDev;
virDomainNetGetActualDirectMode;
virDomainNetGetActualDirectVirtPortProfile;
+virDomainNetGetActualOpenvswitchPortPtr;
virDomainNetGetActualType;
virDomainNetIndexByMac;
virDomainNetInsert;
@@ -738,6 +739,10 @@ virShrinkN;
virNetDevBandwidthFormat;
virNetDevBandwidthParse;
+# netdev_openvswitch_conf.h
+virNetDevOpenvswitchPortFormat;
+virNetDevOpenvswitchPortParse;
+
# netdev_vportprofile_conf.h
virNetDevVPortProfileFormat;
@@ -1145,6 +1150,7 @@ virGetHostUUID;
virSetHostUUIDStr;
virUUIDFormat;
virUUIDGenerate;
+virUUIDGenerateStr;
virUUIDParse;
@@ -1237,10 +1243,16 @@ virNetDevMacVLanCreateWithVPortProfile;
virNetDevMacVLanDeleteWithVPortProfile;
+# virnetdevopenvswitch.h
+virNetDevOpenvswitchAddPort;
+virNetDevOpenvswitchDelPort;
+
+
# virnetdevtap.h
virNetDevTapCreate;
virNetDevTapCreateInBridgePort;
virNetDevTapDelete;
+virNetDevTapDeleteInBridgePort;
# virnetdevveth.h
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index b712da4..1fab77a 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -56,6 +56,7 @@
#include "domain_nwfilter.h"
#include "network/bridge_driver.h"
#include "virnetdev.h"
+#include "virnetdevtap.h"
#include "virnodesuspend.h"
#include "virtime.h"
#include "virtypedparam.h"
@@ -1132,10 +1133,12 @@ static void lxcVmCleanup(lxc_driver_t *driver,
priv->monitorWatch = -1;
for (i = 0 ; i < vm->def->nnets ; i++) {
- ignore_value(virNetDevSetOnline(vm->def->nets[i]->ifname, false));
- ignore_value(virNetDevVethDelete(vm->def->nets[i]->ifname));
-
- networkReleaseActualDevice(vm->def->nets[i]);
+ virDomainNetDefPtr iface = vm->def->nets[i];
+ ignore_value(virNetDevSetOnline(iface->ifname, false));
+ ignore_value(virNetDevVethDelete(iface->ifname));
+ ignore_value(virNetDevTapDeleteInBridgePort(iface->ifname,
+ virDomainNetGetActualOpenvswitchPortPtr(iface)));
+ networkReleaseActualDevice(iface);
}
virDomainConfVMNWFilterTeardown(vm);
@@ -1377,8 +1380,12 @@ static int lxcSetupInterfaces(virConnectPtr conn,
cleanup:
if (ret != 0) {
- for (i = 0 ; i < def->nnets ; i++)
- networkReleaseActualDevice(def->nets[i]);
+ for (i = 0 ; i < def->nnets ; i++) {
+ virDomainNetDefPtr iface = def->nets[i];
+ ignore_value(virNetDevTapDeleteInBridgePort(iface->ifname,
+ virDomainNetGetActualOpenvswitchPortPtr(iface)));
+ networkReleaseActualDevice(iface);
+ }
}
return ret;
}
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 57ebb9f..1423d3f 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1765,7 +1765,8 @@ networkStartNetworkVirtual(struct network_driver *driver,
goto err0;
}
if (virNetDevTapCreateInBridgePort(network->def->bridge,
- &macTapIfName, network->def->mac, 0, false, NULL) < 0) {
+ &macTapIfName, network->def->mac, 0,
+ false, NULL, NULL) < 0) {
VIR_FREE(macTapIfName);
goto err0;
}
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 0e26df1..d6a81f1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -247,7 +247,8 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
err = virNetDevTapCreateInBridgePort(brname, &net->ifname, tapmac,
- vnet_hdr, true, &tapfd);
+ vnet_hdr, true, &tapfd,
+ virDomainNetGetActualOpenvswitchPortPtr(net));
virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
if (err < 0) {
if (template_ifname)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index b4870be..85a004d 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -40,6 +40,7 @@
#include "qemu_cgroup.h"
#include "locking/domain_lock.h"
#include "network/bridge_driver.h"
+#include "virnetdevtap.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -837,7 +838,8 @@ cleanup:
if (iface_connected)
virDomainConfNWFilterTeardown(net);
-
+ ignore_value(virNetDevTapDeleteInBridgePort(net->ifname,
+ virDomainNetGetActualOpenvswitchPortPtr(net)));
networkReleaseActualDevice(net);
}
@@ -1937,7 +1939,8 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,
detach->ifname);
}
}
-
+ ignore_value(virNetDevTapDeleteInBridgePort(detach->ifname,
+ virDomainNetGetActualOpenvswitchPortPtr(detach)));
networkReleaseActualDevice(detach);
if (vm->def->nnets > 1) {
memmove(vm->def->nets + i,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 2d92d66..14eeef8 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -62,6 +62,7 @@
#include "network/bridge_driver.h"
#include "uuid.h"
#include "virtime.h"
+#include "virnetdevtap.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3731,6 +3732,8 @@ void qemuProcessStop(struct qemud_driver *driver,
/* release the physical device (or any other resources used by
* this interface in the network driver
*/
+ ignore_value(virNetDevTapDeleteInBridgePort(net->ifname,
+ virDomainNetGetActualOpenvswitchPortPtr(net)));
networkReleaseActualDevice(net);
}
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 316d558..b8610ea 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -142,7 +142,8 @@ umlConnectTapDevice(virConnectPtr conn,
memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, tapmac,
- 0, true, NULL) < 0) {
+ 0, true, NULL,
+ virDomainNetGetActualOpenvswitchPortPtr(net)) < 0) {
if (template_ifname)
VIR_FREE(net->ifname);
goto error;
diff --git a/src/util/uuid.c b/src/util/uuid.c
index 23822ec..d8188b7 100644
--- a/src/util/uuid.c
+++ b/src/util/uuid.c
@@ -116,6 +116,25 @@ virUUIDGenerate(unsigned char *uuid)
}
/**
+ * virUUIDGenerateString:
+ * @uuid: string of VIR_UUID_STRING_BUFLEN characters to store the UUID
+ *
+ *
+ * Generates a randomized unique identifier
+ * Returns 0 in case of success and -1 in case of failure
+ */
+int
+virUUIDGenerateStr(char *uuidstr)
+{
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ if (virUUIDGenerate(uuid) < 0)
+ return -1;
+ virUUIDFormat(uuid, uuidstr);
+ return 0;
+}
+
+/**
* virUUIDParse:
* @uuidstr: zero terminated string representation of the UUID
* @uuid: array of VIR_UUID_BUFLEN bytes to store the raw UUID
diff --git a/src/util/uuid.h b/src/util/uuid.h
index 7dbfad5..1ae7efb 100644
--- a/src/util/uuid.h
+++ b/src/util/uuid.h
@@ -30,6 +30,7 @@ int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1);
int virUUIDIsValid(unsigned char *uuid);
int virUUIDGenerate(unsigned char *uuid);
+int virUUIDGenerateStr(char *struuid);
int virUUIDParse(const char *uuidstr,
unsigned char *uuid)
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
new file mode 100644
index 0000000..c5bef8d
--- /dev/null
+++ b/src/util/virnetdevopenvswitch.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * 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:
+ * Dan Wendlandt <dan(a)nicira.com>
+ * Kyle Mestery <kmestery(a)cisco.com>
+ * Ansis Atteka <aatteka(a)nicira.com>
+ */
+
+#include <config.h>
+
+#include "virnetdevopenvswitch.h"
+#include "command.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "ignore-value.h"
+#include "virmacaddr.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+/**
+ * virNetDevOpenvswitchAddPort:
+ * @brname: the bridge name
+ * @ifname: the network interface name
+ * @macaddr: the mac address of the virtual interface
+ *
+ * Add an interface to the OVS bridge
+ *
+ * Returns 0 in case of success or -1 in case of failure.
+ */
+int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,
+ const unsigned char *macaddr,
+ virNetDevOpenvswitchPortPtr ovsport)
+{
+ int ret = -1;
+ virCommandPtr cmd = NULL;
+ char macaddrstr[VIR_MAC_STRING_BUFLEN];
+ char *attachedmac_ex_id = NULL;
+ char *ifaceid_ex_id = NULL;
+
+ virMacAddrFormat(macaddr, macaddrstr);
+
+ if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=\"%s\"",
+ macaddrstr) < 0)
+ goto cleanup;
+ if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=\"%s\"",
+ ovsport->InterfaceID) < 0)
+ goto cleanup;
+
+ cmd = virCommandNew(OVSVSCTL);
+ virCommandAddArgList(cmd, "--", "--may-exist", "add-port",
+ brname, ifname,
+ "--", "set", "Interface", ifname, attachedmac_ex_id,
+ "--", "set", "Interface", ifname, ifaceid_ex_id,
+ "--", "set", "Interface", ifname,
+ "external-ids:iface-status=active",
+ NULL);
+
+ if (virCommandRun(cmd, NULL) < 0) {
+ virReportSystemError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to add port %s to OVS bridge %s"),
+ ifname, brname);
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(attachedmac_ex_id);
+ VIR_FREE(ifaceid_ex_id);
+ virCommandFree(cmd);
+ return ret;
+}
+
+/**
+ * virNetDevOpenvswitchDelPort:
+ * @ifname: the network interface name
+ *
+ * Deletes an interface from a OVS bridge
+ *
+ * Returns 0 in case of success or -1 in case of failure.
+ */
+int virNetDevOpenvswitchDelPort(const char *ifname)
+{
+ int ret = -1;
+ virCommandPtr cmd = NULL;
+
+ cmd = virCommandNew(OVSVSCTL);
+ virCommandAddArgList(cmd, "--", "--if-exists", "del-port", ifname, NULL);
+
+ if (virCommandRun(cmd, NULL) < 0) {
+ virReportSystemError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to delete port %s from OVS"), ifname);
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ virCommandFree(cmd);
+ return ret;
+}
diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h
new file mode 100644
index 0000000..210546b
--- /dev/null
+++ b/src/util/virnetdevopenvswitch.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * 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:
+ * Dan Wendlandt <dan(a)nicira.com>
+ * Kyle Mestery <kmestery(a)cisco.com>
+ * Ansis Atteka <aatteka(a)nicira.com>
+ */
+
+#ifndef __VIR_NETDEV_OPENVSWITCH_H__
+# define __VIR_NETDEV_OPENVSWITCH_H__
+
+# include "internal.h"
+# include "util.h"
+
+typedef struct _virNetDevOpenvswitchPort virNetDevOpenvswitchPort;
+typedef virNetDevOpenvswitchPort *virNetDevOpenvswitchPortPtr;
+struct _virNetDevOpenvswitchPort {
+ char InterfaceID[VIR_UUID_STRING_BUFLEN];
+};
+
+int virNetDevOpenvswitchAddPort(const char *brname,
+ const char *ifname,
+ const unsigned char *macaddr,
+ virNetDevOpenvswitchPortPtr ovsport)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+ ATTRIBUTE_RETURN_CHECK;
+
+int virNetDevOpenvswitchDelPort(const char *ifname)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index 2ed53c6..975bb85 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -25,6 +25,7 @@
#include "virnetdevtap.h"
#include "virnetdev.h"
#include "virnetdevbridge.h"
+#include "virnetdevopenvswitch.h"
#include "virterror_internal.h"
#include "virfile.h"
#include "virterror_internal.h"
@@ -249,6 +250,7 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
* @macaddr: desired MAC address (VIR_MAC_BUFLEN long)
* @vnet_hdr: whether to try enabling IFF_VNET_HDR
* @tapfd: file descriptor return value for the new tap device
+ * @ovsport: Open vSwitch specific configuration
*
* This function creates a new tap device on a bridge. @ifname can be either
* a fixed name or a name template with '%d' for dynamic name allocation.
@@ -265,7 +267,8 @@ int virNetDevTapCreateInBridgePort(const char *brname,
const unsigned char *macaddr,
int vnet_hdr,
bool up,
- int *tapfd)
+ int *tapfd,
+ virNetDevOpenvswitchPortPtr ovsport)
{
if (virNetDevTapCreate(ifname, vnet_hdr, tapfd) < 0)
return -1;
@@ -286,8 +289,13 @@ int virNetDevTapCreateInBridgePort(const char *brname,
if (virNetDevSetMTUFromDevice(*ifname, brname) < 0)
goto error;
- if (virNetDevBridgeAddPort(brname, *ifname) < 0)
- goto error;
+ if (ovsport) {
+ if (virNetDevOpenvswitchAddPort(brname, *ifname, macaddr, ovsport) < 0)
+ goto error;
+ } else {
+ if (virNetDevBridgeAddPort(brname, *ifname) < 0)
+ goto error;
+ }
if (virNetDevSetOnline(*ifname, up) < 0)
goto error;
@@ -299,3 +307,21 @@ int virNetDevTapCreateInBridgePort(const char *brname,
return errno;
}
+
+/**
+ * virNetDevTapDeleteInBridgePort:
+ * @ifname: the interface name (or name template)
+ * @ovsport: Open vSwitch specific configuration
+ *
+ * This function detaches tap device from a bridge.
+ *
+ * Returns 0 in case of success or -1 on failure
+ */
+int virNetDevTapDeleteInBridgePort(char *ifname,
+ virNetDevOpenvswitchPortPtr ovsport)
+{
+ int ret = 0;
+ if (ovsport)
+ ret = virNetDevOpenvswitchDelPort(ifname);
+ return ret;
+}
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index fb35ac5..5b16570 100644
--- a/src/util/virnetdevtap.h
+++ b/src/util/virnetdevtap.h
@@ -24,6 +24,7 @@
# define __VIR_NETDEV_TAP_H__
# include "internal.h"
+# include "conf/domain_conf.h"
int virNetDevTapCreate(char **ifname,
int vnet_hdr,
@@ -38,8 +39,13 @@ int virNetDevTapCreateInBridgePort(const char *brname,
const unsigned char *macaddr,
int vnet_hdr,
bool up,
- int *tapfd)
+ int *tapfd,
+ virNetDevOpenvswitchPortPtr ovsport)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_RETURN_CHECK;
+int virNetDevTapDeleteInBridgePort(char *ifname,
+ virNetDevOpenvswitchPortPtr ovsport)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
#endif /* __VIR_NETDEV_TAP_H__ */
--
1.7.5.4
12 years, 9 months
[libvirt] [PATCH] qemu: Fix seamless spice migration
by Jiri Denemark
Calling qemuDomainMigrateGraphicsRelocate notifies spice clients to
connect to destination qemu so that they can seamlessly switch streams
once migration is done. Unfortunately, current qemu is not able to
accept any connections while incoming migration connection is open.
Thus, we need to delay opening the migration connection to the point
spice client is already connected to the destination qemu.
---
src/qemu/qemu_migration.c | 83 +++++++++++++++++++++++++++++---------------
1 files changed, 55 insertions(+), 28 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8453a47..687e77d 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1381,6 +1381,7 @@ cleanup:
enum qemuMigrationDestinationType {
MIGRATION_DEST_HOST,
+ MIGRATION_DEST_CONNECT_HOST,
MIGRATION_DEST_UNIX,
MIGRATION_DEST_FD,
};
@@ -1519,6 +1520,44 @@ cleanup:
}
static int
+qemuMigrationConnect(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ qemuMigrationSpecPtr spec)
+{
+ virNetSocketPtr sock;
+ const char *host;
+ char *port = NULL;
+ int ret = -1;
+
+ host = spec->dest.host.name;
+ if (virAsprintf(&port, "%d", spec->dest.host.port) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ spec->destType = MIGRATION_DEST_FD;
+ spec->dest.fd.qemu = -1;
+
+ if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0)
+ goto cleanup;
+ if (virNetSocketNewConnectTCP(host, port, &sock) == 0) {
+ spec->dest.fd.qemu = virNetSocketDupFD(sock, true);
+ virNetSocketFree(sock);
+ }
+ if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0 ||
+ spec->dest.fd.qemu == -1)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(port);
+ if (ret < 0)
+ VIR_FORCE_CLOSE(spec->dest.fd.qemu);
+ return ret;
+}
+
+static int
qemuMigrationRun(struct qemud_driver *driver,
virDomainObjPtr vm,
const char *cookiein,
@@ -1583,6 +1622,11 @@ qemuMigrationRun(struct qemud_driver *driver,
if (flags & VIR_MIGRATE_NON_SHARED_INC)
migrate_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_INC;
+ /* connect to the destination qemu if needed */
+ if (spec->destType == MIGRATION_DEST_CONNECT_HOST &&
+ qemuMigrationConnect(driver, vm, spec) < 0)
+ goto cleanup;
+
switch (spec->destType) {
case MIGRATION_DEST_HOST:
ret = qemuMonitorMigrateToHost(priv->mon, migrate_flags,
@@ -1590,6 +1634,10 @@ qemuMigrationRun(struct qemud_driver *driver,
spec->dest.host.port);
break;
+ case MIGRATION_DEST_CONNECT_HOST:
+ /* handled above and transformed into MIGRATION_DEST_FD */
+ break;
+
case MIGRATION_DEST_UNIX:
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_UNIX)) {
ret = qemuMonitorMigrateToUnix(priv->mon, migrate_flags,
@@ -1712,7 +1760,6 @@ static int doNativeMigrate(struct qemud_driver *driver,
xmlURIPtr uribits = NULL;
int ret = -1;
qemuMigrationSpec spec;
- char *tmp = NULL;
VIR_DEBUG("driver=%p, vm=%p, uri=%s, cookiein=%s, cookieinlen=%d, "
"cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu",
@@ -1720,6 +1767,7 @@ static int doNativeMigrate(struct qemud_driver *driver,
cookieout, cookieoutlen, flags, resource);
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
+ char *tmp;
/* HACK: source host generates bogus URIs, so fix them up */
if (virAsprintf(&tmp, "tcp://%s", uri + strlen("tcp:")) < 0) {
virReportOOMError();
@@ -1736,41 +1784,20 @@ static int doNativeMigrate(struct qemud_driver *driver,
return -1;
}
- spec.fwdType = MIGRATION_FWD_DIRECT;
-
- if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD)) {
- virNetSocketPtr sock;
-
- spec.destType = MIGRATION_DEST_FD;
- spec.dest.fd.qemu = -1;
-
- if (virAsprintf(&tmp, "%d", uribits->port) < 0) {
- virReportOOMError();
- goto cleanup;
- }
- if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0)
- goto cleanup;
- if (virNetSocketNewConnectTCP(uribits->server, tmp, &sock) == 0) {
- spec.dest.fd.qemu = virNetSocketDupFD(sock, true);
- virNetSocketFree(sock);
- }
- if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0 ||
- spec.dest.fd.qemu == -1)
- goto cleanup;
- } else {
+ if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATE_QEMU_FD))
+ spec.destType = MIGRATION_DEST_CONNECT_HOST;
+ else
spec.destType = MIGRATION_DEST_HOST;
- spec.dest.host.name = uribits->server;
- spec.dest.host.port = uribits->port;
- }
+ spec.dest.host.name = uribits->server;
+ spec.dest.host.port = uribits->port;
+ spec.fwdType = MIGRATION_FWD_DIRECT;
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout,
cookieoutlen, flags, resource, &spec, dconn);
-cleanup:
if (spec.destType == MIGRATION_DEST_FD)
VIR_FORCE_CLOSE(spec.dest.fd.qemu);
- VIR_FREE(tmp);
xmlFreeURI(uribits);
return ret;
--
1.7.8.4
12 years, 9 months