[PATCH v5 05/10] libxl: convert libxl_device_nic_add to an async operation

Roger Pau Monne
Wed, 30 May 2012 13:07:50 -0000

This patch converts libxl_device_nic_add to an ao operation that
waits for device backend to reach state XenbusStateInitWait and then
marks the operation as completed. This is not really useful now, but
will be used by latter patches that will launch hotplug scripts after
we reached the desired xenbus state.

Calls to libxl_device_nic_add have also been moved to occur after the
device model has been launched, so when hotplug scripts are called
from this functions the interfaces already exists.

As usual, libxl_device_nic_add callers have been modified, and the
internal function libxl__device_disk_add has been used if the call was
inside an already running ao.

Changes since v4:

 * Used the macro defined in previous patch to define the generic
   callback to wait for nics to be connected.

Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Roger Pau Monne <roger.pau@citrix.com>
---
 tools/libxl/libxl.c          |   39 ++++++++++++++++++++++++------
 tools/libxl/libxl.h          |    3 +-
 tools/libxl/libxl_create.c   |   53 +++++++++++++++++++++++++++++++++++------
 tools/libxl/libxl_device.c   |    9 ++++---
 tools/libxl/libxl_dm.c       |   40 +++++++++++++++++++++++++++++--
 tools/libxl/libxl_internal.h |   18 ++++++++++++++
 tools/libxl/xl_cmdimpl.c     |    2 +-
 7 files changed, 139 insertions(+), 25 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index b674557..88869f6 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -2026,12 +2026,27 @@ static int libxl__device_from_nic(libxl__gc *gc,
uint32_t domid,
     return 0;
 }

-int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
+int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
+                         const libxl_asyncop_how *ao_how)
 {
-    GC_INIT(ctx);
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__ao_device *device;
+
+    GCNEW(device);
+    libxl__prepare_ao_device(device, ao, NULL);
+    device->callback = device_addrm_aocomplete;
+    libxl__device_nic_add(egc, domid, nic, device);
+
+    return AO_INPROGRESS;
+}
+
+void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
+                           libxl_device_nic *nic, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
     flexarray_t *front;
     flexarray_t *back;
-    libxl__device device;
+    libxl__device *device;
     char *dompath, **l;
     unsigned int nb, rc;

@@ -2062,7 +2077,8 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid,
libxl_device_nic *nic)
         }
     }

-    rc = libxl__device_from_nic(gc, domid, nic, &device);
+    GCNEW(device);
+    rc = libxl__device_from_nic(gc, domid, nic, device);
     if ( rc != 0 ) goto out_free;

     flexarray_append(back, "frontend-id");
@@ -2103,6 +2119,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid,
libxl_device_nic *nic)
     flexarray_append(back, libxl__strdup(gc, nic->bridge));
     flexarray_append(back, "handle");
     flexarray_append(back, libxl__sprintf(gc, "%d", nic->devid));
+    flexarray_append(back, "type");
+    flexarray_append(back, libxl__strdup(gc,
+
libxl_nic_type_to_string(nic->nictype)));

     flexarray_append(front, "backend-id");
     flexarray_append(front, libxl__sprintf(gc, "%d",
nic->backend_domid));
@@ -2113,18 +2132,22 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid,
libxl_device_nic *nic)
     flexarray_append(front, "mac");
     flexarray_append(front, libxl__sprintf(gc,
                                     LIBXL_MAC_FMT,
LIBXL_MAC_BYTES(nic->mac)));
-    libxl__device_generic_add(gc, &device,
+    libxl__device_generic_add(gc, device,
                              libxl__xs_kvs_of_flexarray(gc, back,
back->count),
                              libxl__xs_kvs_of_flexarray(gc, front,
front->count));

-    /* FIXME: wait for plug */
+    aodev->dev = device;
+    aodev->action = DEVICE_CONNECT;
+    libxl__initiate_device_add(egc, aodev);
+
     rc = 0;
 out_free:
     flexarray_free(back);
     flexarray_free(front);
 out:
-    GC_FREE;
-    return rc;
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return;
 }

 static void libxl__device_nic_from_xs_be(libxl__gc *gc,
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index ff0078d..51f2e60 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -666,7 +666,8 @@ char * libxl_device_disk_local_attach(libxl_ctx *ctx,
libxl_device_disk *disk);
 int libxl_device_disk_local_detach(libxl_ctx *ctx, libxl_device_disk *disk);

 /* Network Interfaces */
-int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic
*nic);
+int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
+                         const libxl_asyncop_how *ao_how);
 int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid,
                             libxl_device_nic *nic,
                             const libxl_asyncop_how *ao_how);
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 2dc1cee..1dc8247 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -585,6 +585,13 @@ DEFINE_DEVICES_CALLBACK(domcreate_disk_connected,
                         libxl__domain_create_state,
                         devices, num_devices, domcreate_launch_dm)

+static void domcreate_attach_pci(libxl__egc *egc,
+                                 libxl__domain_create_state *dcs, int rc);
+
+DEFINE_DEVICES_CALLBACK(domcreate_nic_connected,
+                        libxl__domain_create_state,
+                        devices, num_devices, domcreate_attach_pci)
+
 static void domcreate_console_available(libxl__egc *egc,
                                         libxl__domain_create_state *dcs);

@@ -752,13 +759,11 @@ static void domcreate_launch_dm(libxl__egc *egc,
     }

     for (i = 0; i < d_config->num_vifs; i++) {
-        ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
-        if (ret) {
-            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
-                       "cannot add nic %d to domain: %d", i, ret);
-            ret = ERROR_FAIL;
-            goto error_out;
-        }
+        /* We have to init the nic here, because we still haven''t
+         * called libxl_device_nic_add at this point, but qemu needs
+         * the nic information to be complete.
+         */
+        libxl__device_nic_setdefault(gc, &d_config->vifs[i]);
     }
     switch (d_config->c_info.type) {
     case LIBXL_DOMAIN_TYPE_HVM:
@@ -831,7 +836,6 @@ static void domcreate_devmodel_started(libxl__egc *egc,
 {
     libxl__domain_create_state *dcs = CONTAINER_OF(dmss, *dcs, dmss.dm);
     STATE_AO_GC(dmss->spawn.ao);
-    int i;
     libxl_ctx *ctx = CTX;
     int domid = dcs->guest_domid;

@@ -851,6 +855,39 @@ static void domcreate_devmodel_started(libxl__egc *egc,
         }
     }

+    /* Plug nic interfaces */
+    if (!ret && d_config->num_vifs > 0) {
+        /* Attach nics */
+        dcs->num_devices = d_config->num_vifs;
+        libxl__add_nics(egc, ao, domid, d_config, &dcs->devices,
+                        domcreate_nic_connected);
+        return;
+    }
+
+    domcreate_attach_pci(egc, dcs, 0);
+    return;
+
+error_out:
+    assert(ret);
+    domcreate_complete(egc, dcs, ret);
+}
+
+static void domcreate_attach_pci(libxl__egc *egc,
+                                 libxl__domain_create_state *dcs, int rc)
+{
+    STATE_AO_GC(dcs->ao);
+    int i, ret = 0;
+    libxl_ctx *ctx = CTX;
+    int domid = dcs->guest_domid;
+
+    /* convenience aliases */
+    libxl_domain_config *const d_config = dcs->guest_config;
+
+    if (rc) {
+        LOG(ERROR, "error connecting nic devices");
+        goto error_out;
+    }
+
     for (i = 0; i < d_config->num_pcidevs; i++)
         libxl__device_pci_add(gc, domid, &d_config->pcidevs[i], 1);

diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 0beb4bb..de7904a 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -433,8 +433,8 @@ int libxl__ao_device_check_last(libxl__gc *gc,
libxl__ao_device *device,
  *
  * This macro is added to prevent repetition of code.
  */
-#define DEFINE_DEVICES_ADD(type)                                              \
-    void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
+#define DEFINE_DEVICES_ADD(type, name)                                        \
+    void libxl__add_##name##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \
                               libxl_domain_config *d_config,                  \
                               libxl__ao_device **devices,                     \
                               libxl__device_callback *callback)               \
@@ -450,12 +450,13 @@ int libxl__ao_device_check_last(libxl__gc *gc,
libxl__ao_device *device,
         }                                                                     \
                                                                               \
         for (i = 0; i < d_config->num_##type##s; i++) {
\
-            libxl__device_##type##_add(egc, domid,
&d_config->type##s[i],     \
+            libxl__device_##name##_add(egc, domid,
&d_config->type##s[i],     \
                                        &aodev[i]);
\
         }                                                                     \
     }

-DEFINE_DEVICES_ADD(disk)
+DEFINE_DEVICES_ADD(disk, disk)
+DEFINE_DEVICES_ADD(vif, nic)

 #undef DEFINE_DEVICES_ADD

diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index dbd8431..9522a9b 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -680,6 +680,14 @@ DEFINE_DEVICES_CALLBACK(spawn_stub_disk_connected,
                         libxl__stub_dm_spawn_state,
                         devices, num_devices, spawn_stub_launch_dm)

+static void stubdom_pvqemu_cb(libxl__egc *egc,
+                              libxl__stub_dm_spawn_state *sdss,
+                              int rc);
+
+DEFINE_DEVICES_CALLBACK(stubdom_nics_connected,
+                        libxl__stub_dm_spawn_state,
+                        devices, num_devices, stubdom_pvqemu_cb)
+
 static void spaw_stubdom_pvqemu_destroy_cb(libxl__egc *egc,
                                            libxl__destroy_domid_state *dis,
                                            int rc);
@@ -843,9 +851,11 @@ static void spawn_stub_launch_dm(libxl__egc *egc,
      }

     for (i = 0; i < dm_config->num_vifs; i++) {
-        ret = libxl_device_nic_add(ctx, dm_domid, &dm_config->vifs[i]);
-        if (ret)
-            goto out;
+         /* We have to init the nic here, because we still haven''t
+         * called libxl_device_nic_add at this point, but qemu needs
+         * the nic information to be complete.
+         */
+        libxl__device_nic_setdefault(gc, &dm_config->vifs[i]);
     }
     ret = libxl_device_vfb_add(ctx, dm_domid, &dm_config->vfbs[0]);
     if (ret)
@@ -922,9 +932,33 @@ static void spawn_stubdom_pvqemu_cb(libxl__egc *egc,
         CONTAINER_OF(stubdom_dmss, *sdss, pvqemu);
     STATE_AO_GC(sdss->dm.spawn.ao);
     uint32_t dm_domid = sdss->pvqemu.guest_domid;
+    libxl_domain_config *d_config = stubdom_dmss->guest_config;

     if (rc) goto out;

+    if (!rc && d_config->num_vifs > 0) {
+        sdss->num_devices = d_config->num_vifs;
+        libxl__add_nics(egc, ao, dm_domid, d_config, &sdss->devices,
+                        stubdom_nics_connected);
+        return;
+    }
+
+out:
+    stubdom_pvqemu_cb(egc, sdss, rc);
+}
+
+static void stubdom_pvqemu_cb(libxl__egc *egc,
+                              libxl__stub_dm_spawn_state *sdss,
+                              int rc)
+{
+    STATE_AO_GC(sdss->dm.spawn.ao);
+    uint32_t dm_domid = sdss->pvqemu.guest_domid;
+
+    if (rc) {
+        LOGE(ERROR, "error connecting nics devices");
+        goto out;
+    }
+
     rc = libxl_domain_unpause(CTX, dm_domid);
     if (rc) goto out;

diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 6df68a6..49085b4 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1852,6 +1852,11 @@ _hidden void libxl__device_disk_add(libxl__egc *egc,
uint32_t domid,
                                     libxl_device_disk *disk,
                                     libxl__ao_device *aodev);

+/* Internal AO operation to connect a nic device */
+_hidden void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
+                                   libxl_device_nic *nic,
+                                   libxl__ao_device *aodev);
+
 /* Arranges that dev will be added to the guest, and the
  * hotplug scripts will be executed (if necessary). When
  * this is done (or an error happens), the callback in
@@ -1965,6 +1970,19 @@ void libxl__add_disks(libxl__egc *egc, libxl__ao *ao,
uint32_t domid,
                       libxl__ao_device **devices,
                       libxl__device_callback *callback);

+/* Helper function to add a bunch of nics. This should be used when
+ * the caller is inside an async op. "devices" will be prepared by
this
+ * function, so there''s no need to call _prepare before calling this
+ * function.
+ *
+ * The "callback" will be called for each device, and the user is
responsible
+ * for calling libxl__ao_device_check_last on the callback.
+ */
+void libxl__add_nics(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                     libxl_domain_config *d_config,
+                     libxl__ao_device **devices,
+                     libxl__device_callback callback);
+
 /* Macro to define callbacks of libxl__add_*, checks if device is last
  * and calls the function passed as a parameter to this macro with the
  * following syntax; func(libxl__egc *, parent_type *, int rc) */
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index a7fa0b9..1f9b857 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -5232,7 +5232,7 @@ int main_networkattach(int argc, char **argv)
         return 0;
     }

-    if (libxl_device_nic_add(ctx, domid, &nic)) {
+    if (libxl_device_nic_add(ctx, domid, &nic, 0)) {
         fprintf(stderr, "libxl_device_nic_add failed.\n");
         return 1;
     }
--
1.7.7.5 (Apple Git-26)