I think I half assumed this would have been pushed already, but seeing
as it wasn't...
On 12/22/2016 04:45 AM, Michal Privoznik wrote:
Based on work of Mehdi Abaakouk <sileht(a)sileht.net>.
When parsing vhost-user interface XML and no ifname is found we
can try to fill it in in post parse callback. The way this works
is we try to make up interface name from given socket path and
then ask openvswitch wether it knows the interface.
s/wether/whether
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
diff to v2:
- All the review points from v2 worked in
src/libvirt_private.syms | 1 +
src/qemu/qemu_domain.c | 21 +++++---
src/util/virnetdevopenvswitch.c | 58 ++++++++++++++++++++++
src/util/virnetdevopenvswitch.h | 4 ++
tests/Makefile.am | 7 +++
tests/qemuxml2argvmock.c | 8 +++
tests/qemuxml2xmlmock.c | 33 ++++++++++++
.../qemuxml2xmlout-net-vhostuser.xml | 2 +
tests/qemuxml2xmltest.c | 2 +-
9 files changed, 129 insertions(+), 7 deletions(-)
create mode 100644 tests/qemuxml2xmlmock.c
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2d23e462d..9e4e8f83f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2057,6 +2057,7 @@ virNetDevMidonetUnbindPort;
# util/virnetdevopenvswitch.h
virNetDevOpenvswitchAddPort;
virNetDevOpenvswitchGetMigrateData;
+virNetDevOpenvswitchGetVhostuserIfname;
virNetDevOpenvswitchInterfaceStats;
virNetDevOpenvswitchRemovePort;
virNetDevOpenvswitchSetMigrateData;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index acfa69589..eed5745b6 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -41,6 +41,7 @@
#include "domain_addr.h"
#include "domain_event.h"
#include "virtime.h"
+#include "virnetdevopenvswitch.h"
#include "virstoragefile.h"
#include "virstring.h"
#include "virthreadjob.h"
@@ -3028,12 +3029,20 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
def->emulator);
}
- if (dev->type == VIR_DOMAIN_DEVICE_NET &&
- dev->data.net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
- !dev->data.net->model) {
- if (VIR_STRDUP(dev->data.net->model,
- qemuDomainDefaultNetModel(def, qemuCaps)) < 0)
- goto cleanup;
+ if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+ if (dev->data.net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
+ !dev->data.net->model) {
+ if (VIR_STRDUP(dev->data.net->model,
+ qemuDomainDefaultNetModel(def, qemuCaps)) < 0)
+ goto cleanup;
+ }
+ if (dev->data.net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER &&
+ !dev->data.net->ifname) {
+ if (virNetDevOpenvswitchGetVhostuserIfname(
+ dev->data.net->data.vhostuser->data.nix.path,
+ &dev->data.net->ifname) < 0)
+ goto cleanup;
+ }
}
/* set default disk types and drivers */
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
index f003b3b13..d93653317 100644
--- a/src/util/virnetdevopenvswitch.c
+++ b/src/util/virnetdevopenvswitch.c
@@ -377,3 +377,61 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
virCommandFree(cmd);
return ret;
}
+
+/**
+ * virNetDevOpenvswitchVhostuserGetIfname:
+ * @path: the path of the unix socket
+ * @ifname: the retrieved name of the interface
+ *
+ * Retreives the ovs ifname from vhostuser unix socket path.
+ *
+ * Returns: 1 if interface is an openvswitch interface,
+ * 0 if it is not, but no other error occurred,
+ * -1 otherwise.
+ */
+int
+virNetDevOpenvswitchGetVhostuserIfname(const char *path,
+ char **ifname)
+{
+ virCommandPtr cmd = NULL;
+ char *tmpIfname = NULL;
+ char **tokens = NULL;
+ size_t ntokens = 0;
+ int status;
+ int ret = -1;
+
+ /* Openvswitch vhostuser path are hardcoded to
+ * /<runstatedir>/openvswitch/<ifname>
+ * for example: /var/run/openvswitch/dpdkvhostuser0
+ *
+ * so we pick the filename and check it's a openvswitch interface
+ */
+ if ((tokens = virStringSplitCount(path, "/", 0, &ntokens))) {
Seems like a lot of extra work just to pull off the last element of the
path. Why not something using strrchr?
ACK in principal - I think you can decide whether strrchr would be more
useful since it seems you can guarantee that @path has at least a '/' in
it... Probably wouldn't need to strdup below either...
John
+ if (VIR_STRDUP(tmpIfname, tokens[ntokens - 1]) < 0)
+ goto cleanup;
+ }
+
+ if (!tmpIfname) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", "get",
"Interface",
+ tmpIfname, "name", NULL);
+ if (virCommandRun(cmd, &status) < 0 ||
+ status) {
+ /* it's not a openvswitch vhostuser interface. */
+ ret = 0;
+ goto cleanup;
+ }
+
+ *ifname = tmpIfname;
+ tmpIfname = NULL;
+ ret = 1;
+
+ cleanup:
+ virStringListFreeCount(tokens, ntokens);
+ virCommandFree(cmd);
+ VIR_FREE(tmpIfname);
+ return ret;
+}
diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h
index 0f9e1dfa6..8f5faf14e 100644
--- a/src/util/virnetdevopenvswitch.h
+++ b/src/util/virnetdevopenvswitch.h
@@ -52,4 +52,8 @@ int virNetDevOpenvswitchInterfaceStats(const char *ifname,
virDomainInterfaceStatsPtr stats)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+int virNetDevOpenvswitchGetVhostuserIfname(const char *path,
+ char **ifname)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+
#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ecd04e895..c8584fea6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -414,6 +414,7 @@ if WITH_QEMU
test_libraries += libqemumonitortestutils.la \
libqemutestdriver.la \
qemuxml2argvmock.la \
+ qemuxml2xmlmock.la \
qemucaps2xmlmock.la \
qemucapsprobemock.la \
$(NULL)
@@ -571,6 +572,12 @@ qemuxml2argvmock_la_CFLAGS = $(AM_CFLAGS)
qemuxml2argvmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
qemuxml2argvmock_la_LIBADD = $(MOCKLIBS_LIBS)
+qemuxml2xmlmock_la_SOURCES = \
+ qemuxml2xmlmock.c
+qemuxml2xmlmock_la_CFLAGS = $(AM_CFLAGS)
+qemuxml2xmlmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
+qemuxml2xmlmock_la_LIBADD = $(MOCKLIBS_LIBS)
+
qemuxml2xmltest_SOURCES = \
qemuxml2xmltest.c testutilsqemu.c testutilsqemu.h \
testutils.c testutils.h
diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c
index c501b59ac..177b24e0a 100644
--- a/tests/qemuxml2argvmock.c
+++ b/tests/qemuxml2argvmock.c
@@ -28,6 +28,7 @@
#include "virnetdev.h"
#include "virnetdevip.h"
#include "virnetdevtap.h"
+#include "virnetdevopenvswitch.h"
#include "virnuma.h"
#include "virrandom.h"
#include "virscsi.h"
@@ -180,3 +181,10 @@ virCryptoGenerateRandom(size_t nbytes)
return buf;
}
+
+int
+virNetDevOpenvswitchGetVhostuserIfname(const char *path ATTRIBUTE_UNUSED,
+ char **ifname)
+{
+ return VIR_STRDUP(*ifname, "vhost-user0");
+}
diff --git a/tests/qemuxml2xmlmock.c b/tests/qemuxml2xmlmock.c
new file mode 100644
index 000000000..0d3e6f2bd
--- /dev/null
+++ b/tests/qemuxml2xmlmock.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 Red Hat, 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, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Michal Privoznik <mprivozn(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include "virnetdevopenvswitch.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+int
+virNetDevOpenvswitchGetVhostuserIfname(const char *path ATTRIBUTE_UNUSED,
+ char **ifname)
+{
+ return VIR_STRDUP(*ifname, "vhost-user0");
+}
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-vhostuser.xml
b/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-vhostuser.xml
index ac1d7e110..2bdcac358 100644
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-vhostuser.xml
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-vhostuser.xml
@@ -30,12 +30,14 @@
<interface type='vhostuser'>
<mac address='52:54:00:ee:96:6b'/>
<source type='unix' path='/tmp/vhost0.sock'
mode='server'/>
+ <target dev='vhost-user0'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
</interface>
<interface type='vhostuser'>
<mac address='52:54:00:ee:96:6c'/>
<source type='unix' path='/tmp/vhost1.sock'
mode='client'/>
+ <target dev='vhost-user0'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x04' function='0x0'/>
</interface>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index ddd17cb1e..30931f581 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1031,7 +1031,7 @@ mymain(void)
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
-VIRT_TEST_MAIN(mymain)
+VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/qemuxml2xmlmock.so")
#else