[libvirt] [RFC PATCH] Add Qemu Network Helper

From: Richa Marwaha <rmarwah@linux.vnet.ibm.com> QEMU has a new feature which allows QEMU to execute under an unprivileged user ID and still be able to add a tap device to a Linux network bridge. Below is the link to the QEMU patches for the bridge helper feature: http://lists.gnu.org/archive/html/qemu-devel/2012-01/msg03562.html The existing libvirt tap network device support for adding a tap device to a bridge (-netdev tap) works only when connected to a libvirtd instance running as the privileged system account 'root'. When connected to a libvirtd instance running as an unprivileged user (ie. using the session URI) creation of the tap device fails as follows: error: Failed to start domain F14_64 error: Unable to create tap device vnet%d: Operation not permitted With this support, creating a tap device in the above scenario will be possible. Additionally, hot attaching a tap device to a bridge while running when connected to a libvirtd instance running as an unprivileged user will be possible. Signed-off-by: Richa Marwaha <rmarwah@linux.vnet.ibm.com> Signed-off-by: Corey Bryant<coreyb@linux.vnet.ibm.com> --- src/qemu/qemu_command.c | 38 +++++++++++++++++++++++++------------- src/qemu/qemu_command.h | 1 + src/qemu/qemu_hotplug.c | 19 +++++++++++-------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 117542f..daa5381 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2745,6 +2745,7 @@ error: char * qemuBuildHostNetStr(virDomainNetDefPtr net, + struct qemud_driver *driver, char type_sep, int vlan, const char *tapfd, @@ -2753,6 +2754,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, bool is_tap = false; virBuffer buf = VIR_BUFFER_INITIALIZER; enum virDomainNetType netType = virDomainNetGetActualType(net); + const char *brname = NULL; if (net->script && netType != VIR_DOMAIN_NET_TYPE_ETHERNET) { qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -2762,8 +2764,15 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, } switch (netType) { - case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_BRIDGE: + if (!driver->privileged) { + brname = virDomainNetGetActualBridgeName(net); + virBufferAsprintf(&buf, "bridge%cbr=%s", type_sep, brname); + type_sep = ','; + is_tap = true; + break; + } + case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_DIRECT: virBufferAsprintf(&buf, "tap%cfd=%s", type_sep, tapfd); type_sep = ','; @@ -4865,7 +4874,7 @@ qemuBuildCommandLine(virConnectPtr conn, for (i = 0 ; i < def->nnets ; i++) { virDomainNetDefPtr net = def->nets[i]; char *nic, *host; - char tapfd_name[50]; + char tapfd_name[50] = ""; char vhostfd_name[50] = ""; int vlan; int bootindex = bootNet; @@ -4902,17 +4911,20 @@ qemuBuildCommandLine(virConnectPtr conn, if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { - int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net, - qemuCaps); - if (tapfd < 0) - goto error; + if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || + driver->privileged) { + int tapfd = qemuNetworkIfaceConnect(def, conn, driver, net, + qemuCaps); + if (tapfd < 0) + goto error; - last_good_net = i; - virCommandTransferFD(cmd, tapfd); + last_good_net = i; + virCommandTransferFD(cmd, tapfd); - if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", - tapfd) >= sizeof(tapfd_name)) - goto no_memory; + if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", + tapfd) >= sizeof(tapfd_name)) + goto no_memory; + } } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { int tapfd = qemuPhysIfaceConnect(def, driver, net, qemuCaps, vmop); @@ -4955,7 +4967,7 @@ qemuBuildCommandLine(virConnectPtr conn, if (qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) { virCommandAddArg(cmd, "-netdev"); - if (!(host = qemuBuildHostNetStr(net, ',', vlan, + if (!(host = qemuBuildHostNetStr(net, driver, ',', vlan, tapfd_name, vhostfd_name))) goto error; virCommandAddArg(cmd, host); @@ -4978,7 +4990,7 @@ qemuBuildCommandLine(virConnectPtr conn, if (!(qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) && qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { virCommandAddArg(cmd, "-net"); - if (!(host = qemuBuildHostNetStr(net, ',', vlan, + if (!(host = qemuBuildHostNetStr(net, driver, ',', vlan, tapfd_name, vhostfd_name))) goto error; virCommandAddArg(cmd, host); diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 1eafeb3..04240bc 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -62,6 +62,7 @@ qemuBuildChrDeviceStr (virDomainChrDefPtr serial, /* With vlan == -1, use netdev syntax, else old hostnet */ char * qemuBuildHostNetStr(virDomainNetDefPtr net, + struct qemud_driver *driver, char type_sep, int vlan, const char *tapfd, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index ad31eba..7f8b1e4 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -699,12 +699,15 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { - if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net, - priv->qemuCaps)) < 0) - goto cleanup; - iface_connected = true; - if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) - goto cleanup; + if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || + driver->privileged) { + if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net, + priv->qemuCaps)) < 0) + goto cleanup; + iface_connected = true; + if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0) + goto cleanup; + } } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { if ((tapfd = qemuPhysIfaceConnect(vm->def, driver, net, priv->qemuCaps, @@ -752,11 +755,11 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV) && qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { - if (!(netstr = qemuBuildHostNetStr(net, ',', + if (!(netstr = qemuBuildHostNetStr(net, driver, ',', -1, tapfd_name, vhostfd_name))) goto cleanup; } else { - if (!(netstr = qemuBuildHostNetStr(net, ' ', + if (!(netstr = qemuBuildHostNetStr(net, driver, ' ', vlan, tapfd_name, vhostfd_name))) goto cleanup; } -- 1.7.1

On 05/10/2012 09:15 AM, rmarwah@linux.vnet.ibm.com wrote:
From: Richa Marwaha <rmarwah@linux.vnet.ibm.com>
QEMU has a new feature which allows QEMU to execute under an unprivileged user ID and still be able to add a tap device to a Linux network bridge. Below is the link to the QEMU patches for the bridge helper feature:
http://lists.gnu.org/archive/html/qemu-devel/2012-01/msg03562.html
The existing libvirt tap network device support for adding a tap device to a bridge (-netdev tap) works only when connected to a libvirtd instance running as the privileged system account 'root'. When connected to a libvirtd instance running as an unprivileged user (ie. using the session URI) creation of the tap device fails as follows:
error: Failed to start domain F14_64 error: Unable to create tap device vnet%d: Operation not permitted
With this support, creating a tap device in the above scenario will be possible. Additionally, hot attaching a tap device to a bridge while running when connected to a libvirtd instance running as an unprivileged user will be possible.
Signed-off-by: Richa Marwaha <rmarwah@linux.vnet.ibm.com> Signed-off-by: Corey Bryant<coreyb@linux.vnet.ibm.com> --- src/qemu/qemu_command.c | 38 +++++++++++++++++++++++++------------- src/qemu/qemu_command.h | 1 + src/qemu/qemu_hotplug.c | 19 +++++++++++-------- 3 files changed, 37 insertions(+), 21 deletions(-)
Being a new feature, I think this is too late for inclusion in 0.9.12, but looks like a very nice feature to have post-release! I didn't spot anything obviously wrong with the code. Who is responsible for setting up the qemu bridge helper? Is the error message when the bridge helper is not available (qemu too old, or helper is not configured to run, ...) sensible, or does libvirt need an additional qemu_capabilities.h patch to probe for the bridge helper so that libvirt can give a sane error message? -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

Quoting Eric Blake <eblake@redhat.com>:
On 05/10/2012 09:15 AM, rmarwah@linux.vnet.ibm.com wrote:
From: Richa Marwaha <rmarwah@linux.vnet.ibm.com>
QEMU has a new feature which allows QEMU to execute under an unprivileged user ID and still be able to add a tap device to a Linux network bridge. Below is the link to the QEMU patches for the bridge helper feature:
http://lists.gnu.org/archive/html/qemu-devel/2012-01/msg03562.html
The existing libvirt tap network device support for adding a tap device to a bridge (-netdev tap) works only when connected to a libvirtd instance running as the privileged system account 'root'. When connected to a libvirtd instance running as an unprivileged user (ie. using the session URI) creation of the tap device fails as follows:
error: Failed to start domain F14_64 error: Unable to create tap device vnet%d: Operation not permitted
With this support, creating a tap device in the above scenario will be possible. Additionally, hot attaching a tap device to a bridge while running when connected to a libvirtd instance running as an unprivileged user will be possible.
Signed-off-by: Richa Marwaha <rmarwah@linux.vnet.ibm.com> Signed-off-by: Corey Bryant<coreyb@linux.vnet.ibm.com> --- src/qemu/qemu_command.c | 38 +++++++++++++++++++++++++------------- src/qemu/qemu_command.h | 1 + src/qemu/qemu_hotplug.c | 19 +++++++++++-------- 3 files changed, 37 insertions(+), 21 deletions(-)
Being a new feature, I think this is too late for inclusion in 0.9.12, but looks like a very nice feature to have post-release!
I didn't spot anything obviously wrong with the code.
Who is responsible for setting up the qemu bridge helper?
qemu bridge helper just needs some setting for it to run. One of which is to switch ON the setuid bit for bridge helper exec and the second one is ACL file setup. Below is the link that provides the setup and execution information of the qemu bridge helper: http://wiki.qemu.org/Features/HelperNetworking
Is the error message when the bridge helper is not available (qemu too old, or helper is not configured to run, ...) sensible, or does libvirt need an additional qemu_capabilities.h patch to probe for the bridge helper so that libvirt can give a sane error message?
I think we would need to provide a patch to detect the -netdev bridge is supported in qemu_capabilites.c, but the errors that the QEMU issues for mis-configure of the qemu bridge helper provides enough details to figure out reason. Also will provide the AppArmor patch with the next version of the helper patch. https://www.redhat.com/archives/libvir-list/2012-March/msg00575.html Eric I have a question as I am new to community, would the distro provide the bridge config (setuid and ACL File) or libvirt ? Regards Richa Marwaha
-- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
rmarwah@linux.vnet.ibm.com