[libvirt] [PATCH 7/7] Add support for attaching network/bridge NICs in QEMU driver

Mark McLoughlin markmc at redhat.com
Wed Jul 22 21:57:36 UTC 2009


In order to hotplug a network/bridge backed NIC, we need to first create
the tap file descriptor, add the tap interface to the bridge and then
pass the file descriptor to the qemu process using the 'getfd' monitor
command.

Once the tapfd has been accepted, we create the network backend using
host_net_add, supplying the name assigned to the tapfd. If this fails,
we need to close the tapfd in qemu using the 'closefd' monitor command.

* src/qemu_driver.c: add support for tapfd based hotplug in
  qemudDomainAttachNetDevice()
---
 src/qemu_driver.c |   73 +++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index a7861be..23cbd8f 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4620,13 +4620,15 @@ static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
 }
 
 static int qemudDomainAttachNetDevice(virConnectPtr conn,
+                                      struct qemud_driver *driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev,
                                       unsigned int qemuCmdFlags)
 {
     virDomainNetDefPtr net = dev->data.net;
     char *cmd = NULL, *reply = NULL, *remove_cmd = NULL;
-    int i;
+    char *tapfd_name = NULL, *tapfd_close = NULL;
+    int i, tapfd = -1;
     unsigned domain, bus, slot;
 
     if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
@@ -4637,10 +4639,16 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
 
     if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
         net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
-        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
-                         _("network device type '%s' cannot be attached"),
-                         virDomainNetTypeToString(net->type));
-        return -1;
+        if (vm->monitor_chr->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
+            qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                             _("network device type '%s' cannot be attached: "
+                               "qemu is not using a unix socket monitor"),
+                             virDomainNetTypeToString(net->type));
+            return -1;
+        }
+
+        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
+            return -1;
     }
 
     if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
@@ -4658,27 +4666,55 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
         if (vm->def->nets[i]->vlan >= net->vlan)
             net->vlan = vm->def->nets[i]->vlan;
 
-    if (qemuBuildHostNetStr(conn, net,
-                            "host_net_add ", ' ', net->vlan, NULL, &cmd) < 0)
-        goto cleanup;
+    if (tapfd != -1) {
+        if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0)
+            goto no_memory;
+
+        if (virAsprintf(&tapfd_close, "closefd %s", tapfd_name) < 0)
+            goto no_memory;
+
+        if (virAsprintf(&cmd, "getfd %s", tapfd_name) < 0)
+            goto no_memory;
+
+        if (qemudMonitorCommandWithFd(vm, cmd, tapfd, &reply) < 0) {
+            qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                             _("failed to pass fd to qemu with '%s'"), cmd);
+            goto cleanup;
+        }
+
+        DEBUG("%s: getfd reply: %s", vm->def->name, reply);
+
+        VIR_FREE(reply);
+        VIR_FREE(cmd);
+    }
+
+    if (qemuBuildHostNetStr(conn, net, "host_net_add ", ' ',
+                            net->vlan, tapfd_name, &cmd) < 0)
+        goto try_tapfd_close;
 
     remove_cmd = NULL;
     if (net->vlan >= 0 && net->hostnet_name &&
         virAsprintf(&remove_cmd, "host_net_remove %d %s",
                     net->vlan, net->hostnet_name) < 0) {
-        goto no_memory;
+        virReportOOMError(conn);
+        goto try_tapfd_close;
     }
 
     if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
         qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                          _("failed to add network backend with '%s'"), cmd);
-        goto cleanup;
+        goto try_tapfd_close;
     }
 
     DEBUG("%s: host_net_add reply: %s", vm->def->name, reply);
 
     VIR_FREE(reply);
     VIR_FREE(cmd);
+    VIR_FREE(tapfd_name);
+    VIR_FREE(tapfd_close);
+    if (tapfd != -1)
+        close(tapfd);
+    tapfd = -1;
 
     if (qemuBuildNicStr(conn, net,
                         "pci_add pci_addr=auto ", ' ', net->vlan, &cmd) < 0)
@@ -4719,12 +4755,27 @@ try_remove:
         VIR_DEBUG("%s: host_net_remove reply: %s\n", vm->def->name, reply);
     goto cleanup;
 
+try_tapfd_close:
+    VIR_FREE(reply);
+
+    if (tapfd_close) {
+        if (qemudMonitorCommand(vm, tapfd_close, &reply) < 0)
+            VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_close);
+        else
+            VIR_DEBUG("%s: closefd: %s\n", vm->def->name, reply);
+    }
+    goto cleanup;
+
 no_memory:
     virReportOOMError(conn);
 cleanup:
     VIR_FREE(cmd);
     VIR_FREE(reply);
     VIR_FREE(remove_cmd);
+    VIR_FREE(tapfd_close);
+    VIR_FREE(tapfd_name);
+    if (tapfd != -1)
+        close(tapfd);
     return -1;
 }
 
@@ -4854,7 +4905,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
             goto cleanup;
         }
     } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
-        ret = qemudDomainAttachNetDevice(dom->conn, vm, dev, qemuCmdFlags);
+        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
     } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
                dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
                dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
-- 
1.6.2.5




More information about the libvir-list mailing list