vhost-user is a networking backend based on unix domain sockets instead of tap devices and ioctl(). This makes it possible for userspace networking stacks (vswitches) to provide vhost-networking to guests. Signed-off-by: Luke Gorrie <luke@xxxxxxxx> --- docs/schemas/domaincommon.rng | 23 ++++++++ src/conf/domain_conf.c | 42 ++++++++++++++ src/conf/domain_conf.h | 5 ++ src/lxc/lxc_process.c | 1 + src/qemu/qemu_command.c | 66 +++++++++++++++++++++- src/uml/uml_conf.c | 5 ++ src/xenxs/xen_sxpr.c | 1 + tests/qemuxml2argvdata/qemuxml2argv-hugepages.args | 2 +- 8 files changed, 142 insertions(+), 3 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index af67123..30e7daf 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1966,6 +1966,29 @@ <ref name="interface-options"/> </interleave> </group> + <!-- vhostuser interface: specify unix socket path, socket mode --> + <group> + <attribute name="type"> + <value>vhostuser</value> + </attribute> + <interleave> + <optional> + <element name="socket"> + <attribute name="path"> + <ref name="absFilePath"/> + </attribute> + <attribute name="mode"> + <choice> + <value>server</value> + <value>client</value> + </choice> + </attribute> + <empty/> + </element> + </optional> + <ref name="interface-options"/> + </interleave> + </group> <group> <attribute name="type"> <value>network</value> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f1df092..b47554a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -348,6 +348,7 @@ VIR_ENUM_IMPL(virDomainFSWrpolicy, VIR_DOMAIN_FS_WRPOLICY_LAST, VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST, "user", "ethernet", + "vhostuser", "server", "client", "mcast", @@ -1333,6 +1334,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def) VIR_FREE(def->data.ethernet.ipaddr); break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + VIR_FREE(def->data.vhostuser.socket); + VIR_FREE(def->data.vhostuser.mode); + break; + case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: @@ -6579,6 +6585,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, char *script = NULL; char *address = NULL; char *port = NULL; + char *vhostuser_socket = NULL; + char *vhostuser_mode = NULL; char *model = NULL; char *backend = NULL; char *txmode = NULL; @@ -6636,6 +6644,11 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, xmlStrEqual(cur->name, BAD_CAST "source")) { dev = virXMLPropString(cur, "dev"); mode = virXMLPropString(cur, "mode"); + } else if (!vhostuser_socket && !vhostuser_mode && + def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER && + xmlStrEqual(cur->name, BAD_CAST "socket")) { + vhostuser_socket = virXMLPropString(cur, "path"); + vhostuser_mode = virXMLPropString(cur, "mode"); } else if (!def->virtPortProfile && xmlStrEqual(cur->name, BAD_CAST "virtualport")) { if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) { @@ -6804,6 +6817,25 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, } break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + if (vhostuser_socket == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No <socket> 'path' attribute " + "specified with <interface type='vhostuser'/>")); + goto error; + } + if (vhostuser_mode == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No <socket> 'mode' attribute " + "specified with <interface type='vhostuser'/>")); + goto error; + } + def->data.vhostuser.socket = vhostuser_socket; + def->data.vhostuser.mode = vhostuser_mode; + vhostuser_socket = NULL; + vhostuser_mode = NULL; + break; + case VIR_DOMAIN_NET_TYPE_BRIDGE: if (bridge == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -7038,6 +7070,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, VIR_FREE(portgroup); VIR_FREE(address); VIR_FREE(port); + VIR_FREE(vhostuser_socket); + VIR_FREE(vhostuser_mode); VIR_FREE(ifname); VIR_FREE(dev); virDomainActualNetDefFree(actual); @@ -15764,6 +15798,14 @@ virDomainNetDefFormat(virBufferPtr buf, def->data.ethernet.ipaddr); break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + virBufferEscapeString(buf, "<socket path='%s'", + def->data.vhostuser.socket); + virBufferEscapeString(buf, " mode='%s'", + def->data.vhostuser.mode); + virBufferAddLit(buf, "/>\n"); + break; + case VIR_DOMAIN_NET_TYPE_BRIDGE: virBufferEscapeString(buf, "<source bridge='%s'/>\n", def->data.bridge.brname); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8f17c74..b5ea2f6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -791,6 +791,7 @@ struct _virDomainFSDef { enum virDomainNetType { VIR_DOMAIN_NET_TYPE_USER, VIR_DOMAIN_NET_TYPE_ETHERNET, + VIR_DOMAIN_NET_TYPE_VHOSTUSER, VIR_DOMAIN_NET_TYPE_SERVER, VIR_DOMAIN_NET_TYPE_CLIENT, VIR_DOMAIN_NET_TYPE_MCAST, @@ -877,6 +878,10 @@ struct _virDomainNetDef { char *ipaddr; } ethernet; struct { + char *socket; + char *mode; + } vhostuser; + struct { char *address; int port; } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */ diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 0aef13a..854f65d 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -437,6 +437,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_MCAST: diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1d5bce6..755bf9d 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7007,6 +7007,62 @@ qemuBuildGraphicsCommandLine(virQEMUDriverConfigPtr cfg, } static int +qemuBuildVhostuserCommandLine(virCommandPtr cmd, + virDomainDefPtr def, + virDomainNetDefPtr net, + virQEMUCapsPtr qemuCaps) +{ + virBuffer buf1 = VIR_BUFFER_INITIALIZER; + virBuffer buf2 = VIR_BUFFER_INITIALIZER; + + char* nic = NULL; + + if (!qemuDomainSupportsNetdev(def, qemuCaps, net)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Netdev support unavailable")); + goto error; + } + + if (!qemuDomainSupportsNicdev(def, qemuCaps, net)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Nicdev support unavailable")); + goto error; + } + + virBufferAsprintf(&buf1, "socket,id=char%s,path=%s%s", + net->info.alias, net->data.vhostuser.socket, + STRCASEEQ(net->data.vhostuser.mode, "server") ? ",server" : ""); + virBufferAsprintf(&buf2, "type=vhost-user,id=host%s,chardev=char%s", + net->info.alias, net->info.alias); + + if (virBufferError(&buf1) || virBufferError(&buf2)) { + virReportOOMError(); + goto error; + } + + virCommandAddArgList(cmd, "-chardev", virBufferContentAndReset(&buf1), + NULL); + virCommandAddArgList(cmd, "-netdev", virBufferContentAndReset(&buf2), + NULL); + + if (!(nic = qemuBuildNicDevStr(def, net, -1, 0, 0, qemuCaps))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Error generating NIC -device string")); + goto error; + } + + virCommandAddArgList(cmd, "-device", nic, NULL); + + return 0; + +error: + virBufferFreeAndReset(&buf1); + virBufferFreeAndReset(&buf2); + + return -1; +} + +static int qemuBuildInterfaceCommandLine(virCommandPtr cmd, virQEMUDriverPtr driver, virConnectPtr conn, @@ -7029,6 +7085,10 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, int actualType = virDomainNetGetActualType(net); size_t i; + if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + return qemuBuildVhostuserCommandLine(cmd, def, net, qemuCaps); + } + if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { /* NET_TYPE_HOSTDEV devices are really hostdev devices, so * their commandlines are constructed with other hostdevs. @@ -7374,8 +7434,10 @@ qemuBuildCommandLine(virConnectPtr conn, def->emulator); goto error; } - virCommandAddArgList(cmd, "-mem-prealloc", "-mem-path", - cfg->hugepagePath, NULL); + virCommandAddArg(cmd, "-mem-path"); + virCommandAddArgFormat(cmd, "%s,prealloc=on,share=%s", + cfg->hugepagePath, + def->mem.nosharepages ? "off" : "on"); } if (def->mem.locked && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_MLOCK)) { diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 464d56d..d33d9b4 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -182,6 +182,11 @@ umlBuildCommandLineNet(virConnectPtr conn, } break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("vhostuser networking type not supported")); + goto error; + case VIR_DOMAIN_NET_TYPE_SERVER: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("TCP server networking type not supported")); diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index 29316a4..ca26694 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -1933,6 +1933,7 @@ xenFormatSxprNet(virConnectPtr conn, virBufferEscapeSexpr(buf, "(ip '%s')", def->data.ethernet.ipaddr); break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_CLIENT: diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hugepages.args b/tests/qemuxml2argvdata/qemuxml2argv-hugepages.args index d42d9fc..5f8df71 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-hugepages.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-hugepages.args @@ -1,5 +1,5 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \ /usr/bin/qemu -S -M \ -pc -m 214 -mem-prealloc -mem-path /dev/hugepages/libvirt/qemu -smp 1 \ +pc -m 214 -mem-path /dev/hugepages/libvirt/qemu,prealloc=on,share=on -smp 1 \ -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -hda \ /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -- 1.9.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list