From: Richa Marwaha <rmarwah(a)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(a)linux.vnet.ibm.com>
Signed-off-by: Corey Bryant<coreyb(a)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