[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 3 of 5] tools/libxl: setup/teardown Remus network buffering



On 26/08/2013 00:45, rshriram@xxxxxxxxx wrote:
> # HG changeset patch
> # User Shriram Rajagopalan <rshriram@xxxxxxxxx>
> # Date 1377473609 25200
> # Node ID 4b23104828c09218aa7f9fbde1578bb6706e13d6
> # Parent  4d24d36d30c37e4fb5985952db92c1e789c90894
> tools/libxl: setup/teardown Remus network buffering
>
> Setup/teardown remus network buffering for a given guest, when
> libxl_domain_remus_start API is invoked.
>
> This patch does the following during setup:
>  a) call the hotplug script for each vif to setup its network buffer
>
>  b) establish a dedicated remus context containing libnl related
>     state (netlink sockets, qdisc caches, etc.,)
>
>  c) Obtain handles to plug qdiscs installed on the IFB devices
>     chosen by the hotplug scripts.
>
> During teardown, the hotplug scripts are called to remove the IFB
> devices. This is followed by releasing netlink resources.
>
> Signed-off-by: Shriram Rajagopalan <rshriram@xxxxxxxxx>
>
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/Makefile
> --- a/tools/libxl/Makefile    Sun Aug 25 16:33:27 2013 -0700
> +++ b/tools/libxl/Makefile    Sun Aug 25 16:33:29 2013 -0700
> @@ -40,6 +40,13 @@ LIBXL_OBJS-y += libxl_blktap2.o
>  else
>  LIBXL_OBJS-y += libxl_noblktap2.o
>  endif
> +
> +ifeq ($(CONFIG_REMUS_NETBUF),y)
> +LIBXL_OBJS-y += libxl_netbuffer.o
> +else
> +LIBXL_OBJS-y += libxl_nonetbuffer.o
> +endif
> +
>  LIBXL_OBJS-$(CONFIG_X86) += libxl_cpuid.o libxl_x86.o
>  LIBXL_OBJS-$(CONFIG_IA64) += libxl_nocpuid.o libxl_noarch.o
>  LIBXL_OBJS-$(CONFIG_ARM) += libxl_nocpuid.o libxl_noarch.o
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/libxl.c
> --- a/tools/libxl/libxl.c     Sun Aug 25 16:33:27 2013 -0700
> +++ b/tools/libxl/libxl.c     Sun Aug 25 16:33:29 2013 -0700
> @@ -692,8 +692,9 @@ libxl_vminfo * libxl_list_vm(libxl_ctx *
>      return ptr;
>  }
>  
> -static void remus_failover_cb(libxl__egc *egc,
> -                              libxl__domain_suspend_state *dss, int rc);
> +static void remus_replication_failure_cb(libxl__egc *egc,
> +                                         libxl__domain_suspend_state *dss,
> +                                         int rc);
>  
>  /* TODO: Explicit Checkpoint acknowledgements via recv_fd. */
>  int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info,
> @@ -712,18 +713,44 @@ int libxl_domain_remus_start(libxl_ctx *
>  
>      GCNEW(dss);
>      dss->ao = ao;
> -    dss->callback = remus_failover_cb;
> +    dss->callback = remus_replication_failure_cb;
>      dss->domid = domid;
>      dss->fd = send_fd;
>      /* TODO do something with recv_fd */
>      dss->type = type;
>      dss->live = 1;
>      dss->debug = 0;
> -    dss->remus = info;
>  
>      assert(info);
>  
> -    /* TBD: Remus setup - i.e. attach qdisc, enable disk buffering, etc */
> +    GCNEW(dss->remus_ctx);
> +
> +    /* convenience shorthand */
> +    libxl__remus_ctx *remus_ctx = dss->remus_ctx;
> +    remus_ctx->blackhole = info->blackhole;
> +    remus_ctx->interval = info->interval;
> +    remus_ctx->compression = info->compression;
> +
> +    /* Setup network buffering before invoking domain_suspend */
> +    if (info->netbuf) {
> +        if (info->netbufscript) {
> +            remus_ctx->netbufscript =
> +                libxl__strdup(gc, info->netbufscript);
> +        } else {
> +            remus_ctx->netbufscript =
> +                libxl__sprintf(gc, "%s/remus-netbuf-setup",
> +                              libxl__xen_script_dir_path());
> +        }
> +
> +        if (libxl__remus_netbuf_setup(gc, domid, remus_ctx)) {
> +            LOG(ERROR, "Remus: failed to setup network buffering"
> +                " for guest with domid %u", domid);
> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +    }
> +
> +    /* TBD: enable disk buffering */
>  
>      /* Point of no return */
>      libxl__domain_suspend(egc, dss);
> @@ -733,8 +760,9 @@ int libxl_domain_remus_start(libxl_ctx *
>      return AO_ABORT(rc);
>  }
>  
> -static void remus_failover_cb(libxl__egc *egc,
> -                              libxl__domain_suspend_state *dss, int rc)
> +static void remus_replication_failure_cb(libxl__egc *egc,
> +                                         libxl__domain_suspend_state *dss,
> +                                         int rc)
>  {
>      STATE_AO_GC(dss->ao);
>      /*
> @@ -743,9 +771,10 @@ static void remus_failover_cb(libxl__egc
>       * from sending checkpoints.
>       */
>  
> -    /* TBD: Remus cleanup - i.e. detach qdisc, release other
> -     * resources.
> -     */
> +    /* Teardown the network buffers and release netlink resources. */
> +    if (dss->remus_ctx && dss->remus_ctx->netbuf_ctx)
> +        libxl__remus_netbuf_teardown(gc, dss->domid, dss->remus_ctx);
> +
>      libxl__ao_complete(egc, ao, rc);
>  }
>  
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/libxl_dom.c
> --- a/tools/libxl/libxl_dom.c Sun Aug 25 16:33:27 2013 -0700
> +++ b/tools/libxl/libxl_dom.c Sun Aug 25 16:33:29 2013 -0700
> @@ -1259,7 +1259,7 @@ static void remus_checkpoint_dm_saved(li
>      /* REMUS TODO: Wait for disk and memory ack, release network buffer */
>      /* REMUS TODO: make this asynchronous */
>      assert(!rc); /* REMUS TODO handle this error properly */
> -    usleep(dss->interval * 1000);
> +    usleep(dss->remus_ctx->interval * 1000);
>      libxl__xc_domain_saverestore_async_callback_done(egc, &dss->shs, 1);
>  }
>  
> @@ -1277,7 +1277,6 @@ void libxl__domain_suspend(libxl__egc *e
>      const libxl_domain_type type = dss->type;
>      const int live = dss->live;
>      const int debug = dss->debug;
> -    const libxl_domain_remus_info *const r_info = dss->remus;
>      libxl__srm_save_autogen_callbacks *const callbacks =
>          &dss->shs.callbacks.save.a;
>  
> @@ -1312,9 +1311,8 @@ void libxl__domain_suspend(libxl__egc *e
>      dss->guest_responded = 0;
>      dss->dm_savefile = libxl__device_model_savefile(gc, domid);
>  
> -    if (r_info != NULL) {
> -        dss->interval = r_info->interval;
> -        if (r_info->compression)
> +    if (dss->remus_ctx != NULL) {
> +        if (dss->remus_ctx->compression)

This can be reduced to:

if (dss->remus_ctx && dss->remus_ctx->compression)

~Andrew

>              dss->xcflags |= XCFLAGS_CHECKPOINT_COMPRESS;
>      }
>  
> @@ -1335,7 +1333,7 @@ void libxl__domain_suspend(libxl__egc *e
>      }
>  
>      memset(callbacks, 0, sizeof(*callbacks));
> -    if (r_info != NULL) {
> +    if (dss->remus_ctx != NULL) {
>          callbacks->suspend = libxl__remus_domain_suspend_callback;
>          callbacks->postcopy = libxl__remus_domain_resume_callback;
>          callbacks->checkpoint = libxl__remus_domain_checkpoint_callback;
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/libxl_internal.h
> --- a/tools/libxl/libxl_internal.h    Sun Aug 25 16:33:27 2013 -0700
> +++ b/tools/libxl/libxl_internal.h    Sun Aug 25 16:33:29 2013 -0700
> @@ -2242,6 +2242,29 @@ typedef struct libxl__logdirty_switch {
>      libxl__ev_time timeout;
>  } libxl__logdirty_switch;
>  
> +typedef struct libxl__remus_ctx {
> +    /* checkpoint interval */
> +    int interval;
> +    int blackhole;
> +    int compression;
> +    /* Script to setup/teardown network buffers */
> +    const char *netbufscript;
> +    /* Opaque context containing network buffer related stuff */
> +    void *netbuf_ctx;
> +} libxl__remus_ctx;
> +
> +_hidden int libxl__remus_netbuf_setup(libxl__gc *gc, uint32_t domid,
> +                                     libxl__remus_ctx *remus_ctx);
> +
> +_hidden int libxl__remus_netbuf_teardown(libxl__gc *gc, uint32_t domid,
> +                                        libxl__remus_ctx *remus_ctx);
> +
> +_hidden int libxl__remus_netbuf_start_new_epoch(libxl__gc *gc, uint32_t 
> domid,
> +                                               libxl__remus_ctx *remus_ctx);
> +
> +_hidden int libxl__remus_netbuf_release_prev_epoch(libxl__gc *gc, uint32_t 
> domid,
> +                                                  libxl__remus_ctx 
> *remus_ctx);
> +
>  struct libxl__domain_suspend_state {
>      /* set by caller of libxl__domain_suspend */
>      libxl__ao *ao;
> @@ -2252,7 +2275,7 @@ struct libxl__domain_suspend_state {
>      libxl_domain_type type;
>      int live;
>      int debug;
> -    const libxl_domain_remus_info *remus;
> +    libxl__remus_ctx *remus_ctx;
>      /* private */
>      xc_evtchn *xce; /* event channel handle */
>      int suspend_eventchn;
> @@ -2260,7 +2283,6 @@ struct libxl__domain_suspend_state {
>      int xcflags;
>      int guest_responded;
>      const char *dm_savefile;
> -    int interval; /* checkpoint interval (for Remus) */
>      libxl__save_helper_state shs;
>      libxl__logdirty_switch logdirty;
>      /* private for libxl__domain_save_device_model */
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/libxl_netbuffer.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/tools/libxl/libxl_netbuffer.c   Sun Aug 25 16:33:29 2013 -0700
> @@ -0,0 +1,434 @@
> +/*
> + * Copyright (C) 2013
> + * Author Shriram Rajagopalan <rshriram@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#include "libxl_osdeps.h" /* must come before any other headers */
> +
> +#include "libxl_internal.h"
> +
> +#include <netlink/cache.h>
> +#include <netlink/socket.h>
> +#include <netlink/attr.h>
> +#include <netlink/route/link.h>
> +#include <netlink/route/route.h>
> +#include <netlink/route/qdisc.h>
> +#include <netlink/route/qdisc/plug.h>
> +
> +typedef struct libxl__remus_netbuf_ctx {
> +    struct rtnl_qdisc **netbuf_qdisc_list;
> +    struct nl_sock *nlsock;
> +    struct nl_cache *qdisc_cache;
> +    char **vif_list;
> +    char **ifb_list;
> +    uint32_t num_netbufs;
> +    uint32_t unused;
> +} libxl__remus_netbuf_ctx;
> +
> +/* If the device has a vifname, then use that instead of
> + * the vifX.Y format.
> + */
> +static char *get_vifname(libxl__gc *gc, uint32_t domid,
> +                         libxl_device_nic *nic)
> +{
> +    char *vifname = NULL;
> +    vifname = libxl__xs_read(gc, XBT_NULL,
> +                             libxl__sprintf(gc,
> +                                            "%s/backend/vif/%d/%d/vifname",
> +                                            libxl__xs_get_dompath(gc, 0),
> +                                            domid, nic->devid));
> +    if (!vifname) {
> +        vifname = (char *)libxl__device_nic_devname(gc, domid,
> +                                                    nic->devid,
> +                                                    nic->nictype);
> +    }
> +
> +    return vifname;
> +}
> +
> +static char **get_guest_vif_list(libxl__gc *gc, uint32_t domid,
> +                                 int *num_vifs)
> +{
> +    libxl_device_nic *nics;
> +    int nb, i = 0;
> +    char **vif_list = NULL;
> +
> +    nics = libxl_device_nic_list(CTX, domid, &nb);
> +    if (!nics) {
> +        *num_vifs = 0;
> +        return NULL;
> +    }
> +
> +    vif_list = libxl__calloc(gc, nb, sizeof(char *));
> +    for (i = 0; i < nb; ++i) {
> +        vif_list[i] = get_vifname(gc, domid, &nics[i]);
> +        libxl_device_nic_dispose(&nics[i]);
> +    }
> +    free(nics);
> +
> +    *num_vifs = nb;
> +    return vif_list;
> +}
> +
> +static void netbuf_script_child_death_cb(libxl__egc *egc,
> +                                         libxl__ev_child *child,
> +                                         pid_t pid, int status)
> +{
> +    /* No-op. hotplug-error will be read in setup/teardown_ifb */
> +    return;
> +}
> +
> +/* the script needs the following env & args
> + * $vifname
> + * $XENBUS_PATH (/libxl/<domid>/remus/netbuf/<devid>/)
> + * setup/teardown as command line arg.
> + * In return, the script writes the name of IFB device to be used for
> + * output buffering into XENBUS_PATH/ifb
> + *
> + * The setup and teardown ops are synchronous, as they are executed during
> + * the context of an asynchronous API call (libxl_domain_remus_start).
> + */
> +static int libxl__exec_netbuf_script(libxl__gc *gc, uint32_t domid,
> +                                     int devid, char *vif, char *script,
> +                                     char *op)
> +{
> +    int arraysize, nr;
> +    char **env = NULL, **args = NULL;
> +    pid_t pid;
> +    libxl__ev_child childw_out;
> +
> +    arraysize = 5; nr = 0;
> +    GCNEW_ARRAY(env, arraysize);
> +    env[nr++] = "vifname";
> +    env[nr++] = vif;
> +    env[nr++] = "XENBUS_PATH";
> +    env[nr++] = GCSPRINTF("%s/remus/netbuf/%d",
> +                          libxl__xs_libxl_path(gc, domid), devid);
> +    env[nr++] = NULL;
> +    assert(nr <= arraysize);
> +
> +    arraysize = 3; nr = 0;
> +    GCNEW_ARRAY(args, arraysize);
> +    args[nr++] = script;
> +    args[nr++] = op;
> +    args[nr++] = NULL;
> +    assert(nr == arraysize);
> +
> +    libxl__ev_child_init(&childw_out);
> +    LOG(DEBUG, "Calling netbuf script: %s %s", script, op);
> +
> +    /* Fork and exec netbuf script */
> +    pid = libxl__ev_child_fork(gc, &childw_out, 
> netbuf_script_child_death_cb);
> +    if (pid == -1) {
> +        LOG(ERROR, "unable to fork netbuf script %s", script);
> +        return ERROR_FAIL;
> +    }
> +
> +    if (!pid) {
> +        /* child: Launch netbuf script */
> +        libxl__exec(gc, -1, -1, -1, args[0], args, env);
> +        /* notreached */
> +        abort();
> +    }
> +
> +    assert(libxl__ev_child_inuse(&childw_out));
> +
> +    return 0;
> +}
> +
> +static int script_done_cb(libxl__gc *gc, uint32_t domid,
> +                          const char *state, void *userdata)
> +{
> +    return 0; /* No-op callback */
> +}
> +
> +static int libxl__netbuf_script_setup(libxl__gc *gc, uint32_t domid,
> +                                      int devid, char *vif, char *script,
> +                                      char **ifb)
> +{
> +    int rc;
> +    char *out_path_base, *hotplug_error;
> +
> +    rc = libxl__exec_netbuf_script(gc, domid, devid, vif,
> +                                   script, "setup");
> +    if (rc) return rc;
> +
> +    out_path_base = GCSPRINTF("%s/remus/netbuf/%d",
> +                              libxl__xs_libxl_path(gc, domid), devid);
> +
> +    /* Now wait for the result (XENBUS_PATH/hotplug-status).
> +     * It doesnt matter what the result is. If the hotplug-status path
> +     * appears, then we are good to go.
> +     */
> +    rc = libxl__wait_for_offspring(gc, domid, LIBXL_HOTPLUG_TIMEOUT,
> +                                   script,
> +                                   /* path */
> +                                   GCSPRINTF("%s/hotplug-status",
> +                                             out_path_base),
> +                                   NULL /* state */,
> +                                   NULL, script_done_cb, NULL);
> +    if (rc) {
> +        LOG(ERROR, "unable to wait for %s setup to complete", script);
> +        return ERROR_FAIL;
> +    }
> +
> +    hotplug_error = libxl__xs_read(gc, XBT_NULL,
> +                                   GCSPRINTF("%s/hotplug-error",
> +                                             out_path_base));
> +    if (hotplug_error) {
> +        LOG(ERROR, "netbuf script %s setup failed: %s",
> +            script, hotplug_error);
> +        return ERROR_FAIL;
> +    }
> +
> +    *ifb = libxl__xs_read(gc, XBT_NULL,
> +                          GCSPRINTF("%s/remus/netbuf/%d/ifb",
> +                                    libxl__xs_libxl_path(gc, domid),
> +                                    devid));
> +    if (!(*ifb)) {
> +        LOG(ERROR, "Cannot get ifb dev name for domain %u dev %s",
> +            domid, vif);
> +        return ERROR_FAIL;
> +    }
> +
> +    return 0;
> +}
> +
> +static int libxl__netbuf_script_teardown(libxl__gc *gc, uint32_t domid,
> +                                         int devid, char *vif,
> +                                         char *script)
> +{
> +    /* Nothing to wait for during tear down */
> +    return libxl__exec_netbuf_script(gc, domid, devid, vif,
> +                                     script, "teardown");
> +}
> +
> +/* Scan through the list of vifs belonging to domid and
> + * invoke the netbufscript to setup the IFB device & plug qdisc
> + * for each vif. Then scan through the list of IFB devices to obtain
> + * a handle on the plug qdisc installed on these IFB devices.
> + * Network output buffering is controlled via these qdiscs.
> + */
> +int libxl__remus_netbuf_setup(libxl__gc *gc, uint32_t domid,
> +                           libxl__remus_ctx *remus_ctx)
> +{
> +    int i, ret, ifindex, num_netbufs = 0;
> +    struct rtnl_link *ifb = NULL;
> +    struct rtnl_qdisc *qdisc = NULL;
> +    libxl__remus_netbuf_ctx *netbuf_ctx = NULL;
> +
> +    /* If the domain backend is a stubdom, do nothing. We dont
> +     * support stubdom network buffering yet.
> +     */
> +    if (libxl_get_stubdom_id(CTX, domid)) {
> +        LOG(ERROR, "Network buffering is not supported with stubdoms");
> +        return ERROR_FAIL;
> +    }
> +
> +    netbuf_ctx = libxl__zalloc(gc, sizeof(libxl__remus_netbuf_ctx));
> +    netbuf_ctx->vif_list = get_guest_vif_list(gc, domid, &num_netbufs);
> +    if (!num_netbufs) return 0;
> +
> +    netbuf_ctx->ifb_list = libxl__calloc(gc, num_netbufs,
> +                                         sizeof(char *));
> +
> +    /* convenience vars */
> +    char **vif_list = netbuf_ctx->vif_list;
> +    char **ifb_list = netbuf_ctx->ifb_list;
> +
> +    for (i = 0; i < num_netbufs; ++i) {
> +
> +        /* The setup script does the following
> +         * find a free IFB to act as buffer for the vif.
> +         * set up the plug qdisc on the IFB.
> +         */
> +        ret = libxl__netbuf_script_setup(gc, domid, i, vif_list[i],
> +                                         (char *) remus_ctx->netbufscript,
> +                                         &ifb_list[i]);
> +        if (ret) {
> +            LOG(ERROR, "Failed to setup ifb device for dev %s",
> +                vif_list[i]);
> +            return ERROR_FAIL;
> +        }
> +
> +        LOG(DEBUG, "dev %s will be buffered at ifb %s", vif_list[i],
> +            ifb_list[i]);
> +    }
> +
> +    /* Now that we have brought up IFB devices with plug qdisc for
> +     * each vif, lets get a netlink handle on the plug qdisc for use
> +     * during checkpointing.
> +     */
> +    netbuf_ctx->nlsock = nl_socket_alloc();
> +    if (!netbuf_ctx->nlsock) {
> +        LOG(ERROR, "cannot allocate nl socket");
> +        return ERROR_FAIL;
> +    }
> +
> +    ret = nl_connect(netbuf_ctx->nlsock, NETLINK_ROUTE);
> +    if (ret) {
> +        LOG(ERROR, "failed to open netlink socket: %s",
> +            nl_geterror(ret));
> +        return ERROR_FAIL;
> +    }
> +
> +    /* get list of all qdiscs installed on network devs. */
> +    ret = rtnl_qdisc_alloc_cache(netbuf_ctx->nlsock,
> +                                 &netbuf_ctx->qdisc_cache);
> +    if (ret) {
> +        LOG(ERROR, "failed to allocate qdisc cache: %s",
> +            nl_geterror(ret));
> +        goto end;
> +    }
> +
> +    /* list of handles to plug qdiscs */
> +    netbuf_ctx->netbuf_qdisc_list =
> +        libxl__calloc(gc, num_netbufs,
> +                      sizeof(struct rtnl_qdisc *));
> +
> +    ifb = rtnl_link_alloc();
> +
> +    for (i = 0; i < num_netbufs; ++i) {
> +
> +        /* get a handle to the IFB interface */
> +        ret = rtnl_link_get_kernel(netbuf_ctx->nlsock, 0,
> +                                   ifb_list[i], &ifb);
> +        if (ret) {
> +            LOG(ERROR, "cannot obtain handle for %s: %s", ifb_list[i],
> +                nl_geterror(ret));
> +            goto end;
> +        }
> +
> +        ifindex = rtnl_link_get_ifindex(ifb);
> +        if (!ifindex) {
> +            LOG(ERROR, "interface %s has no index", ifb_list[i]);
> +            goto end;
> +        }
> +
> +        /* Get a reference to the root qdisc installed on the IFB, by
> +         * querying the qdisc list we obtained earlier. The netbufscript
> +         * sets up the plug qdisc as the root qdisc, so we dont have to
> +         * search the entire qdisc tree on the IFB dev.
> +
> +         * There is no need to explicitly free this qdisc as its just a
> +         * reference from the qdisc cache we allocated earlier.
> +         */
> +        qdisc = rtnl_qdisc_get_by_parent(netbuf_ctx->qdisc_cache, ifindex,
> +                                         TC_H_ROOT);
> +
> +        if (qdisc) {
> +            const char *tc_kind = rtnl_tc_get_kind(TC_CAST(qdisc));
> +            /* Sanity check: Ensure that the root qdisc is a plug qdisc. */
> +            if (!tc_kind || strcmp(tc_kind, "plug")) {
> +                LOG(ERROR, "plug qdisc is not installed on %s", ifb_list[i]);
> +                goto end;
> +            }
> +            netbuf_ctx->netbuf_qdisc_list[i] = qdisc;
> +        } else {
> +            LOG(ERROR, "Cannot get qdisc handle from ifb %s", ifb_list[i]);
> +            goto end;
> +        }
> +    }
> +
> +    rtnl_link_put(ifb);
> +
> +    netbuf_ctx->num_netbufs = num_netbufs;
> +
> +    /* Update remus_ctx to point to the newly setup netbuffer context */
> +    remus_ctx->netbuf_ctx = netbuf_ctx;
> +    return 0;
> +
> + end:
> +    if (ifb) rtnl_link_put(ifb);
> +    if (netbuf_ctx->qdisc_cache) nl_cache_free(netbuf_ctx->qdisc_cache);
> +    if (netbuf_ctx->nlsock) nl_close(netbuf_ctx->nlsock);
> +    return ERROR_FAIL;
> +}
> +
> +/* Note: This function will be called in the same gc context as
> + * libxl__remus_netbuf_setup, created during the libxl_domain_remus_start
> + * API call.
> + */
> +int libxl__remus_netbuf_teardown(libxl__gc *gc, uint32_t domid,
> +                              libxl__remus_ctx *remus_ctx)
> +{
> +    libxl__remus_netbuf_ctx *netbuf_ctx = remus_ctx->netbuf_ctx;
> +    char **vif_list = NULL, **ifb_list = NULL;
> +    int i;
> +
> +    if (!(remus_ctx && netbuf_ctx && netbuf_ctx->num_netbufs))
> +        return 0;
> +
> +    nl_cache_free(netbuf_ctx->qdisc_cache);
> +    nl_close(netbuf_ctx->nlsock);
> +
> +    vif_list = netbuf_ctx->vif_list;
> +    ifb_list = netbuf_ctx->ifb_list;
> +
> +    for (i = 0; i < netbuf_ctx->num_netbufs; ++i)
> +        libxl__netbuf_script_teardown(gc, domid, i, vif_list[i],
> +                                      (char *) remus_ctx->netbufscript);
> +
> +    return 0;
> +}
> +
> +#define TC_BUFFER_START 1
> +#define TC_BUFFER_RELEASE 2
> +static int remus_netbuf_op(libxl__gc *gc, uint32_t domid,
> +                        libxl__remus_ctx *remus_ctx,
> +                        int buffer_op)
> +{
> +    int i, ret;
> +    libxl__remus_netbuf_ctx *netbuf_ctx = remus_ctx->netbuf_ctx;
> +
> +    for (i = 0; i < netbuf_ctx->num_netbufs; ++i) {
> +        if (buffer_op == TC_BUFFER_START)
> +            ret = rtnl_qdisc_plug_buffer(netbuf_ctx->netbuf_qdisc_list[i]);
> +        else
> +            ret = 
> rtnl_qdisc_plug_release_one(netbuf_ctx->netbuf_qdisc_list[i]);
> +
> +        if (!ret)
> +            ret = rtnl_qdisc_add(netbuf_ctx->nlsock,
> +                                 netbuf_ctx->netbuf_qdisc_list[i],
> +                                 NLM_F_REQUEST);
> +        if (ret) {
> +            LOG(ERROR, "Remus: cannot do netbuf op %s on %s:%s",
> +                ((buffer_op == TC_BUFFER_START) ?
> +                 "start_new_epoch" : "release_prev_epoch"),
> +                netbuf_ctx->ifb_list[i], nl_geterror(ret));
> +            return ERROR_FAIL;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +int libxl__remus_netbuf_start_new_epoch(libxl__gc *gc, uint32_t domid,
> +                                     libxl__remus_ctx *remus_ctx)
> +{
> +    return remus_netbuf_op(gc, domid, remus_ctx, TC_BUFFER_START);
> +}
> +
> +int libxl__remus_netbuf_release_prev_epoch(libxl__gc *gc, uint32_t domid,
> +                                        libxl__remus_ctx *remus_ctx)
> +{
> +    return remus_netbuf_op(gc, domid, remus_ctx, TC_BUFFER_RELEASE);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/libxl_nonetbuffer.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/tools/libxl/libxl_nonetbuffer.c Sun Aug 25 16:33:29 2013 -0700
> @@ -0,0 +1,54 @@
> +/*
> + * Copyright (C) 2013
> + * Author Shriram Rajagopalan <rshriram@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#include "libxl_osdeps.h" /* must come before any other headers */
> +
> +#include "libxl_internal.h"
> +
> +/* Remus network buffer related stubs */
> +int libxl__remus_netbuf_setup(libxl__gc *gc, uint32_t domid,
> +                           libxl__remus_ctx *remus_ctx)
> +{
> +    LOG(ERROR, "Remus: No support for network buffering");
> +    return ERROR_FAIL;
> +}
> +
> +int libxl__remus_netbuf_teardown(libxl__gc *gc, uint32_t domid,
> +                              libxl__remus_ctx *remus_ctx)
> +{
> +    return 0; /* No point complaining in a teardown call. */
> +}
> +
> +int libxl__remus_netbuf_start_new_epoch(libxl__gc *gc, uint32_t domid,
> +                                     libxl__remus_ctx *remus_ctx)
> +{
> +    LOG(ERROR, "Remus: No support for network buffering");
> +    return ERROR_FAIL;
> +}
> +
> +int libxl__remus_netbuf_release_prev_epoch(libxl__gc *gc, uint32_t domid,
> +                                        libxl__remus_ctx *remus_ctx)
> +{
> +    LOG(ERROR, "Remus: No support for network buffering");
> +    return ERROR_FAIL;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff -r 4d24d36d30c3 -r 4b23104828c0 tools/libxl/libxl_types.idl
> --- a/tools/libxl/libxl_types.idl     Sun Aug 25 16:33:27 2013 -0700
> +++ b/tools/libxl/libxl_types.idl     Sun Aug 25 16:33:29 2013 -0700
> @@ -526,6 +526,8 @@ libxl_domain_remus_info = Struct("domain
>      ("interval",     integer),
>      ("blackhole",    bool),
>      ("compression",  bool),
> +    ("netbuf",  bool),
> +    ("netbufscript", string),
>      ])
>  
>  libxl_event_type = Enumeration("event_type", [
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxx
> http://lists.xen.org/xen-devel


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.