/src/locking/qemu-sanlock.conf
/src/locking/test_libvirt_sanlock.aug
/src/lxc/test_libvirtd_lxc.aug
+/src/lxc/lxc_controller_dispatch.h
+/src/lxc/lxc_monitor_dispatch.h
+/src/lxc/lxc_protocol.c
+/src/lxc/lxc_protocol.h
/src/qemu/test_libvirtd_qemu.aug
/src/remote/*_client_bodies.h
/src/remote/*_protocol.[ch]
XEN_DRIVER_SOURCES += xen/xen_inotify.c xen/xen_inotify.h
endif
+LXC_PROTOCOL_GENERATED = \
+ $(srcdir)/lxc/lxc_protocol.h \
+ $(srcdir)/lxc/lxc_protocol.c \
+ $(NULL)
+
+LXC_MONITOR_GENERATED = \
+ $(srcdir)/lxc/lxc_monitor_dispatch.h \
+ $(NULL)
+
+LXC_CONTROLLER_GENERATED = \
+ $(srcdir)/lxc/lxc_controller_dispatch.h \
+ $(NULL)
+
+LXC_GENERATED = \
+ $(LXC_PROTOCOL_GENERATED) \
+ $(LXC_MONITOR_GENERATED) \
+ $(LXC_CONTROLLER_GENERATED) \
+ $(NULL)
+
+LXC_PROTOCOL = $(srcdir)/lxc/lxc_protocol.x
+
+$(srcdir)/lxc/lxc_monitor_dispatch.h: $(srcdir)/rpc/gendispatch.pl \
+ $(LXC_PROTOCOL)
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl \
+ -k virLXCProtocol VIR_LXC_PROTOCOL $(LXC_PROTOCOL) > $@
+
+$(srcdir)/lxc/lxc_controller_dispatch.h: $(srcdir)/rpc/gendispatch.pl \
+ $(REMOTE_PROTOCOL)
+ $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl \
+ -b virLXCProtocol VIR_LXC_PROTOCOL $(LXC_PROTOCOL) > $@
+
+EXTRA_DIST += \
+ $(LXC_PROTOCOL) \
+ $(LXC_GENERATED) \
+ $(NULL)
+
+BUILT_SOURCES += $(LXC_GENERATED)
+
LXC_DRIVER_SOURCES = \
+ $(LXC_PROTOCOL_GENERATED) \
+ $(LXC_MONITOR_GENERATED) \
lxc/lxc_conf.c lxc/lxc_conf.h \
lxc/lxc_container.c lxc/lxc_container.h \
lxc/lxc_cgroup.c lxc/lxc_cgroup.h \
lxc/lxc_driver.c lxc/lxc_driver.h
LXC_CONTROLLER_SOURCES = \
+ $(LXC_PROTOCOL_GENERATED) \
+ $(LXC_CONTROLLER_GENERATED) \
lxc/lxc_conf.c lxc/lxc_conf.h \
lxc/lxc_container.c lxc/lxc_container.h \
lxc/lxc_cgroup.c lxc/lxc_cgroup.h \
#include "lxc_conf.h"
#include "lxc_container.h"
#include "lxc_cgroup.h"
+#include "lxc_protocol.h"
#include "virnetdev.h"
#include "virnetdevveth.h"
#include "memory.h"
/* Server socket */
virNetServerPtr server;
+ virNetServerClientPtr client;
+ virNetServerProgramPtr prog;
+ bool inShutdown;
+ int timerShutdown;
};
+#include "lxc_controller_dispatch.h"
+
static void virLXCControllerFree(virLXCControllerPtr ctrl);
+static void virLXCControllerQuitTimer(int timer ATTRIBUTE_UNUSED, void *opaque)
+{
+ virLXCControllerPtr ctrl = opaque;
+
+ VIR_DEBUG("Triggering event loop quit");
+ virNetServerQuit(ctrl->server);
+}
+
+
static virLXCControllerPtr virLXCControllerNew(const char *name)
{
virLXCControllerPtr ctrl = NULL;
if (VIR_ALLOC(ctrl) < 0)
goto no_memory;
+ ctrl->timerShutdown = -1;
+
if (!(ctrl->name = strdup(name)))
goto no_memory;
0)) == NULL)
goto error;
+ if ((ctrl->timerShutdown = virEventAddTimeout(-1,
+ virLXCControllerQuitTimer, ctrl,
+ NULL)) < 0)
+ goto error;
+
cleanup:
VIR_FREE(configFile);
virCapabilitiesFree(caps);
virDomainDefFree(ctrl->def);
VIR_FREE(ctrl->name);
+ if (ctrl->timerShutdown != -1)
+ virEventRemoveTimeout(ctrl->timerShutdown);
+
virNetServerFree(ctrl->server);
VIR_FREE(ctrl);
}
+static void virLXCControllerClientCloseHook(virNetServerClientPtr client)
+{
+ virLXCControllerPtr ctrl = virNetServerClientGetPrivateData(client);
+
+ VIR_DEBUG("Client %p has closed", client);
+ if (ctrl->client == client)
+ ctrl->client = NULL;
+ if (ctrl->inShutdown) {
+ VIR_DEBUG("Arm timer to quit event loop");
+ virEventUpdateTimeout(ctrl->timerShutdown, 0);
+ }
+}
+
static int virLXCControllerClientHook(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
void *opaque)
{
virLXCControllerPtr ctrl = opaque;
virNetServerClientSetPrivateData(client, ctrl, NULL);
+ virNetServerClientSetCloseHook(client, virLXCControllerClientCloseHook);
+ VIR_DEBUG("Got new client %p", client);
+ ctrl->client = client;
return 0;
}
virNetServerServiceFree(svc);
svc = NULL;
+ if (!(ctrl->prog = virNetServerProgramNew(VIR_LXC_PROTOCOL_PROGRAM,
+ VIR_LXC_PROTOCOL_PROGRAM_VERSION,
+ virLXCProtocolProcs,
+ virLXCProtocolNProcs)))
+ goto error;
+
virNetServerUpdateServices(ctrl->server, true);
VIR_FREE(sockpath);
return 0;
}
+static void
+virLXCControllerEventSend(virLXCControllerPtr ctrl,
+ int procnr,
+ xdrproc_t proc,
+ void *data)
+{
+ virNetMessagePtr msg;
+
+ if (!ctrl->client)
+ return;
+
+ VIR_DEBUG("Send event %d client=%p", procnr, ctrl->client);
+ if (!(msg = virNetMessageNew(false)))
+ goto error;
+
+ msg->header.prog = virNetServerProgramGetID(ctrl->prog);
+ msg->header.vers = virNetServerProgramGetVersion(ctrl->prog);
+ msg->header.proc = procnr;
+ msg->header.type = VIR_NET_MESSAGE;
+ msg->header.serial = 1;
+ msg->header.status = VIR_NET_OK;
+
+ if (virNetMessageEncodeHeader(msg) < 0)
+ goto error;
+
+ if (virNetMessageEncodePayload(msg, proc, data) < 0)
+ goto error;
+
+ VIR_DEBUG("Queue event %d %zu", procnr, msg->bufferLength);
+ virNetServerClientSendMessage(ctrl->client, msg);
+
+ xdr_free(proc, data);
+ return;
+
+error:
+ virNetMessageFree(msg);
+ xdr_free(proc, data);
+}
+
+
+static int
+virLXCControllerEventSendExit(virLXCControllerPtr ctrl,
+ int exitstatus)
+{
+ virLXCProtocolExitEventMsg msg;
+
+ VIR_DEBUG("Exit status %d", exitstatus);
+ memset(&msg, 0, sizeof(msg));
+ switch (exitstatus) {
+ case 0:
+ msg.status = VIR_LXC_PROTOCOL_EXIT_STATUS_SHUTDOWN;
+ break;
+ default:
+ msg.status = VIR_LXC_PROTOCOL_EXIT_STATUS_ERROR;
+ break;
+ }
+
+ virLXCControllerEventSend(ctrl,
+ VIR_LXC_PROTOCOL_PROC_EXIT_EVENT,
+ (xdrproc_t)xdr_virLXCProtocolExitEventMsg,
+ (void*)&msg);
+
+ if (ctrl->client) {
+ VIR_DEBUG("Waiting for client to complete dispatch");
+ ctrl->inShutdown = true;
+ virNetServerClientDelayedClose(ctrl->client);
+ virNetServerRun(ctrl->server);
+ }
+ VIR_DEBUG("Client has gone away");
+ return 0;
+}
+
+
static int
virLXCControllerRun(virLXCControllerPtr ctrl)
{
rc = virLXCControllerMain(ctrl);
+ virLXCControllerEventSendExit(ctrl, rc);
+
cleanup:
VIR_FORCE_CLOSE(control[0]);
VIR_FORCE_CLOSE(control[1]);
virLXCControllerFree(ctrl);
- return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+ return rc < 0? EXIT_FAILURE : EXIT_SUCCESS;
}
struct _virLXCDomainObjPrivate {
virLXCMonitorPtr monitor;
bool doneStopEvent;
+ int stopReason;
};
void virLXCDomainSetPrivateDataHooks(virCapsPtr caps);
#include "lxc_monitor.h"
#include "lxc_conf.h"
+#include "lxc_protocol.h"
+#include "lxc_monitor_dispatch.h"
#include "memory.h"
virLXCMonitorCallbacksPtr cb;
virNetClientPtr client;
+ virNetClientProgramPtr program;
};
static void virLXCMonitorFree(virLXCMonitorPtr mon);
+static void
+virLXCMonitorHandleEventExit(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
+static virNetClientProgramEvent virLXCProtocolEvents[] = {
+ { VIR_LXC_PROTOCOL_PROC_EXIT_EVENT,
+ virLXCMonitorHandleEventExit,
+ sizeof(virLXCProtocolExitEventMsg),
+ (xdrproc_t)xdr_virLXCProtocolExitEventMsg },
+};
+
+
+static void
+virLXCMonitorHandleEventExit(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virLXCMonitorPtr mon = opaque;
+ virLXCProtocolExitEventMsg *msg = evdata;
+
+ VIR_DEBUG("Event exit %d", msg->status);
+ if (mon->cb->exitNotify)
+ mon->cb->exitNotify(mon, msg->status, mon->vm);
+}
static void virLXCMonitorEOFNotify(virNetClientPtr client ATTRIBUTE_UNUSED,
virLXCMonitorCallbackEOFNotify eofNotify;
virDomainObjPtr vm;
+ VIR_DEBUG("EOF notify");
virLXCMonitorLock(mon);
eofNotify = mon->cb->eofNotify;
vm = mon->vm;
goto error;
+ if (!(mon->program = virNetClientProgramNew(VIR_LXC_PROTOCOL_PROGRAM,
+ VIR_LXC_PROTOCOL_PROGRAM_VERSION,
+ virLXCProtocolEvents,
+ ARRAY_CARDINALITY(virLXCProtocolEvents),
+ mon)))
+ goto error;
+
+ if (virNetClientAddProgram(mon->client,
+ mon->program) < 0)
+ goto error;
+
mon->vm = vm;
mon->cb = cb;
if (mon->cb && mon->cb->destroy)
(mon->cb->destroy)(mon, mon->vm);
virMutexDestroy(&mon->lock);
+ virNetClientProgramFree(mon->program);
VIR_FREE(mon);
}
# define __LXC_MONITOR_H__
# include "domain_conf.h"
+# include "lxc_protocol.h"
typedef struct _virLXCMonitor virLXCMonitor;
typedef virLXCMonitor *virLXCMonitorPtr;
typedef void (*virLXCMonitorCallbackEOFNotify)(virLXCMonitorPtr mon,
virDomainObjPtr vm);
+typedef void (*virLXCMonitorCallbackExitNotify)(virLXCMonitorPtr mon,
+ virLXCProtocolExitStatus status,
+ virDomainObjPtr vm);
+
struct _virLXCMonitorCallbacks {
virLXCMonitorCallbackDestroy destroy;
virLXCMonitorCallbackEOFNotify eofNotify;
+ virLXCMonitorCallbackExitNotify exitNotify;
};
virLXCMonitorPtr virLXCMonitorNew(virDomainObjPtr vm,
virLXCDomainObjPrivatePtr priv = vm->privateData;
virNetDevVPortProfilePtr vport = NULL;
+ VIR_DEBUG("Stopping VM name=%s pid=%d reason=%d",
+ vm->def->name, (int)vm->pid, (int)reason);
+
/* now that we know it's stopped call the hook if present */
if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
char *xml = virDomainDefFormat(vm->def, 0);
if (!priv->doneStopEvent) {
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+ priv->stopReason);
virDomainAuditStop(vm, "shutdown");
} else {
VIR_DEBUG("Stop event has already been sent");
}
}
+static void virLXCProcessMonitorExitNotify(virLXCMonitorPtr mon ATTRIBUTE_UNUSED,
+ virLXCProtocolExitStatus status,
+ virDomainObjPtr vm)
+{
+ virLXCDomainObjPrivatePtr priv = vm->privateData;
+
+ switch (status) {
+ case VIR_LXC_PROTOCOL_EXIT_STATUS_SHUTDOWN:
+ priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
+ break;
+ case VIR_LXC_PROTOCOL_EXIT_STATUS_ERROR:
+ priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
+ break;
+ default:
+ priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
+ break;
+ }
+ VIR_DEBUG("Domain shutoff reason %d (from status %d)",
+ priv->stopReason, status);
+}
static virLXCMonitorCallbacks monitorCallbacks = {
.eofNotify = virLXCProcessMonitorEOFNotify,
.destroy = virLXCProcessMonitorDestroy,
+ .exitNotify = virLXCProcessMonitorExitNotify,
};
virCgroupPtr group = NULL;
int rc;
+ VIR_DEBUG("Stopping VM name=%s pid=%d reason=%d",
+ vm->def->name, (int)vm->pid, (int)reason);
if (vm->pid <= 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid PID %d for container"), vm->pid);
goto cleanup;
}
+ priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
vm->def->id = vm->pid;
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
priv->doneStopEvent = false;
--- /dev/null
+/* -*- c -*-
+ * Define wire protocol for communication between the
+ * LXC driver in libvirtd, and the LXC controller in
+ * the libvirt_lxc helper program.
+ */
+
+enum virLXCProtocolExitStatus {
+ VIR_LXC_PROTOCOL_EXIT_STATUS_ERROR,
+ VIR_LXC_PROTOCOL_EXIT_STATUS_SHUTDOWN
+};
+
+struct virLXCProtocolExitEventMsg {
+ enum virLXCProtocolExitStatus status;
+};
+
+const VIR_LXC_PROTOCOL_PROGRAM = 0x12341234;
+const VIR_LXC_PROTOCOL_PROGRAM_VERSION = 1;
+
+enum virLXCProtocolProcedure {
+ VIR_LXC_PROTOCOL_PROC_EXIT_EVENT = 1 /* skipgen skipgen */
+};