From 509eb51e7ce91c0506858e5c5542527ab90aff0f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 21 Dec 2012 14:20:04 +0000 Subject: [PATCH] Implement the RPC protocol for the libvirt-lxc.la library Add the infrastructure for the libvirt-lxc.la library to the remote protocol client and daemon Signed-off-by: Daniel P. Berrange --- daemon/Makefile.am | 13 ++++- daemon/libvirtd.c | 14 +++++ daemon/libvirtd.h | 1 + daemon/remote.c | 52 +++++++++++++++++ daemon/remote.h | 3 + src/Makefile.am | 19 ++++++- src/remote/lxc_protocol.x | 49 ++++++++++++++++ src/remote/remote_driver.c | 112 +++++++++++++++++++++++++++++-------- 8 files changed, 237 insertions(+), 26 deletions(-) create mode 100644 src/remote/lxc_protocol.x diff --git a/daemon/Makefile.am b/daemon/Makefile.am index f2572724ec..72c619077a 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -17,7 +17,9 @@ CLEANFILES = DAEMON_GENERATED = \ $(srcdir)/remote_dispatch.h \ - $(srcdir)/qemu_dispatch.h + $(srcdir)/lxc_dispatch.h \ + $(srcdir)/qemu_dispatch.h \ + $(NULL) DAEMON_SOURCES = \ libvirtd.c libvirtd.h \ @@ -25,12 +27,14 @@ DAEMON_SOURCES = \ remote.c remote.h \ stream.c stream.h \ ../src/remote/remote_protocol.c \ + ../src/remote/lxc_protocol.c \ ../src/remote/qemu_protocol.c \ $(DAEMON_GENERATED) DISTCLEANFILES = EXTRA_DIST = \ remote_dispatch.h \ + lxc_dispatch.h \ qemu_dispatch.h \ libvirtd.conf \ libvirtd.init.in \ @@ -54,6 +58,7 @@ EXTRA_DIST = \ BUILT_SOURCES = REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x +LXC_PROTOCOL = $(top_srcdir)/src/remote/lxc_protocol.x QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x $(srcdir)/remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ @@ -61,6 +66,11 @@ $(srcdir)/remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ $(AM_V_GEN)$(PERL) -w $(srcdir)/../src/rpc/gendispatch.pl -b remote REMOTE \ $(REMOTE_PROTOCOL) > $@ +$(srcdir)/lxc_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ + $(LXC_PROTOCOL) + $(AM_V_GEN)$(PERL) -w $(srcdir)/../src/rpc/gendispatch.pl -b lxc LXC \ + $(LXC_PROTOCOL) > $@ + $(srcdir)/qemu_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ $(QEMU_PROTOCOL) $(AM_V_GEN)$(PERL) -w $(srcdir)/../src/rpc/gendispatch.pl -b qemu QEMU \ @@ -117,6 +127,7 @@ libvirtd_LDADD += ../src/libvirt_probes.lo endif libvirtd_LDADD += \ + ../src/libvirt-lxc.la \ ../src/libvirt-qemu.la if ! WITH_DRIVER_MODULES diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 9cdf4d9d64..abd9bf26d9 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -103,6 +103,7 @@ virNetSASLContextPtr saslCtxt = NULL; #endif virNetServerProgramPtr remoteProgram = NULL; virNetServerProgramPtr qemuProgram = NULL; +virNetServerProgramPtr lxcProgram = NULL; enum { VIR_DAEMON_ERR_NONE = 0, @@ -1370,6 +1371,18 @@ int main(int argc, char **argv) { goto cleanup; } + if (!(lxcProgram = virNetServerProgramNew(LXC_PROGRAM, + LXC_PROTOCOL_VERSION, + lxcProcs, + lxcNProcs))) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + if (virNetServerAddProgram(srv, lxcProgram) < 0) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + if (!(qemuProgram = virNetServerProgramNew(QEMU_PROGRAM, QEMU_PROTOCOL_VERSION, qemuProcs, @@ -1475,6 +1488,7 @@ int main(int argc, char **argv) { cleanup: virNetlinkEventServiceStopAll(); virObjectUnref(remoteProgram); + virObjectUnref(lxcProgram); virObjectUnref(qemuProgram); virNetServerClose(srv); virObjectUnref(srv); diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index 6b5ceb7ae9..c07637a294 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -32,6 +32,7 @@ # include # include # include "remote_protocol.h" +# include "lxc_protocol.h" # include "qemu_protocol.h" # include "virlog.h" # include "virthread.h" diff --git a/daemon/remote.c b/daemon/remote.c index 913db19fa9..20c3858673 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -50,6 +50,7 @@ #include "virprocess.h" #include "remote_protocol.h" #include "qemu_protocol.h" +#include "lxc_protocol.h" #define VIR_FROM_THIS VIR_FROM_RPC @@ -105,6 +106,7 @@ remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors, #include "remote_dispatch.h" #include "qemu_dispatch.h" +#include "lxc_dispatch.h" /* Prototypes */ @@ -4620,6 +4622,56 @@ cleanup: return rv; } +static int +lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + lxc_domain_open_namespace_args *args) +{ + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + int *fdlist = NULL; + int ret; + virDomainPtr dom = NULL; + size_t i; + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(priv->conn, args->dom))) + goto cleanup; + + ret = virDomainLxcOpenNamespace(dom, + &fdlist, + args->flags); + if (ret < 0) + goto cleanup; + + /* We shouldn't have received any from the client, + * but in case they're playing games with us, prevent + * a resource leak + */ + for (i = 0 ; i < msg->nfds ; i++) + VIR_FORCE_CLOSE(msg->fds[i]); + VIR_FREE(msg->fds); + msg->nfds = 0; + + msg->fds = fdlist; + msg->nfds = ret; + + rv = 1; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virDomainFree(dom); + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/daemon/remote.h b/daemon/remote.h index 493171f76d..d42a19e92e 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -32,6 +32,9 @@ extern virNetServerProgramProc remoteProcs[]; extern size_t remoteNProcs; +extern virNetServerProgramProc lxcProcs[]; +extern size_t lxcNProcs; + extern virNetServerProgramProc qemuProcs[]; extern size_t qemuNProcs; diff --git a/src/Makefile.am b/src/Makefile.am index 83c27230d1..b1318c55a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -272,19 +272,28 @@ REMOTE_DRIVER_GENERATED = \ $(srcdir)/remote/remote_protocol.c \ $(srcdir)/remote/remote_protocol.h \ $(srcdir)/remote/remote_client_bodies.h \ + $(srcdir)/remote/lxc_protocol.c \ + $(srcdir)/remote/lxc_protocol.h \ + $(srcdir)/remote/lxc_client_bodies.h \ $(srcdir)/remote/qemu_protocol.c \ $(srcdir)/remote/qemu_protocol.h \ $(srcdir)/remote/qemu_client_bodies.h REMOTE_PROTOCOL = $(srcdir)/remote/remote_protocol.x +LXC_PROTOCOL = $(srcdir)/remote/lxc_protocol.x QEMU_PROTOCOL = $(srcdir)/remote/qemu_protocol.x -REMOTE_DRIVER_PROTOCOL = $(REMOTE_PROTOCOL) $(QEMU_PROTOCOL) +REMOTE_DRIVER_PROTOCOL = $(REMOTE_PROTOCOL) $(QEMU_PROTOCOL) $(LXC_PROTOCOL) $(srcdir)/remote/remote_client_bodies.h: $(srcdir)/rpc/gendispatch.pl \ $(REMOTE_PROTOCOL) $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl \ -k remote REMOTE $(REMOTE_PROTOCOL) > $@ +$(srcdir)/remote/lxc_client_bodies.h: $(srcdir)/rpc/gendispatch.pl \ + $(LXC_PROTOCOL) + $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl \ + -k lxc LXC $(LXC_PROTOCOL) > $@ + $(srcdir)/remote/qemu_client_bodies.h: $(srcdir)/rpc/gendispatch.pl \ $(QEMU_PROTOCOL) $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl \ @@ -318,7 +327,7 @@ EXTRA_DIST += $(REMOTE_DRIVER_PROTOCOL) \ # The alternation of the following regexps matches both cases. r1 = /\* \d+ \*/ r2 = /\* <[[:xdigit:]]+> \S+:\d+ \*/ -struct_prefix = (remote_|qemu_|virNet|keepalive_) +struct_prefix = (remote_|qemu_|lxc_|virNet|keepalive_) PDWTAGS = \ $(AM_V_GEN)if (pdwtags --help) > /dev/null 2>&1; then \ @@ -374,6 +383,7 @@ EXTRA_DIST += check-symfile.pl check-symsorting.pl PROTOCOL_STRUCTS = \ $(srcdir)/remote_protocol-structs \ + $(srcdir)/lxc_protocol-structs \ $(srcdir)/qemu_protocol-structs \ $(srcdir)/virnetprotocol-structs \ $(srcdir)/virkeepaliveprotocol-structs @@ -382,7 +392,9 @@ check-protocol: $(PROTOCOL_STRUCTS) $(PROTOCOL_STRUCTS:structs=struct) # The .o file that pdwtags parses is created as a side effect of running # libtool; but from make's perspective we depend on the .lo file. -$(srcdir)/remote_protocol-struct $(srcdir)/qemu_protocol-struct: \ +$(srcdir)/remote_protocol-struct \ + $(srcdir)/qemu_protocol-struct \ + $(srcdir)/lxc_protocol-struct: \ $(srcdir)/%-struct: libvirt_driver_remote_la-%.lo $(PDWTAGS) $(srcdir)/virnetprotocol-struct $(srcdir)/virkeepaliveprotocol-struct: \ @@ -1546,6 +1558,7 @@ tapset_DATA = libvirt_probes.stp libvirt_qemu_probes.stp libvirt_functions.stp RPC_PROBE_FILES = $(srcdir)/rpc/virnetprotocol.x \ $(srcdir)/rpc/virkeepaliveprotocol.x \ $(srcdir)/remote/remote_protocol.x \ + $(srcdir)/remote/lxc_protocol.x \ $(srcdir)/remote/qemu_protocol.x libvirt_functions.stp: $(RPC_PROBE_FILES) $(srcdir)/rpc/gensystemtap.pl diff --git a/src/remote/lxc_protocol.x b/src/remote/lxc_protocol.x new file mode 100644 index 0000000000..1453f8940b --- /dev/null +++ b/src/remote/lxc_protocol.x @@ -0,0 +1,49 @@ +/* -*- c -*- + * lxc_protocol.x: private protocol for communicating between + * remote_internal driver and libvirtd. This protocol is + * internal and may change at any time. + * + * Copyright (C) 2010-2013 Red Hat, Inc. + * + * This library 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Daniel Berrange + */ + +%#include "internal.h" +%#include "remote_protocol.h" + +/*----- Protocol. -----*/ +struct lxc_domain_open_namespace_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + + +/* Define the program number, protocol version and procedure numbers here. */ +const LXC_PROGRAM = 0x00068000; +const LXC_PROTOCOL_VERSION = 1; + +enum lxc_procedure { + /* Each function must have a three-word comment. The first word is + * whether gendispatch.pl handles daemon, the second whether + * it handles src/remote. + * The last argument describes priority of API. There are two accepted + * values: low, high; Each API that might eventually access hypervisor's + * monitor (and thus block) MUST fall into low priority. However, there + * are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY + * be marked as high priority. If in doubt, it's safe to choose low. */ + LXC_PROC_DOMAIN_OPEN_NAMESPACE = 1 /* skipgen skipgen priority:low */ +}; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 916ded5916..a9072bbca6 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -37,6 +37,7 @@ #include "virbuffer.h" #include "remote_driver.h" #include "remote_protocol.h" +#include "lxc_protocol.h" #include "qemu_protocol.h" #include "viralloc.h" #include "virutil.h" @@ -77,6 +78,7 @@ struct private_data { virNetClientPtr client; virNetClientProgramPtr remoteProgram; virNetClientProgramPtr qemuProgram; + virNetClientProgramPtr lxcProgram; int counter; /* Serial number for RPC */ @@ -95,6 +97,7 @@ struct private_data { enum { REMOTE_CALL_QEMU = (1 << 0), + REMOTE_CALL_LXC = (1 << 1), }; @@ -112,10 +115,13 @@ static int call(virConnectPtr conn, struct private_data *priv, unsigned int flags, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret); -static int callWithFD(virConnectPtr conn, struct private_data *priv, - unsigned int flags, int fd, int proc_nr, - xdrproc_t args_filter, char *args, - xdrproc_t ret_filter, char *ret); +static int callFull(virConnectPtr conn, struct private_data *priv, + unsigned int flags, + int *fdin, size_t fdinlen, + int **fdout, size_t *fdoutlen, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret); static int remoteAuthenticate(virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth, const char *authtype); #if WITH_SASL @@ -768,6 +774,12 @@ doRemoteOpen(virConnectPtr conn, ARRAY_CARDINALITY(remoteDomainEvents), conn))) goto failed; + if (!(priv->lxcProgram = virNetClientProgramNew(LXC_PROGRAM, + LXC_PROTOCOL_VERSION, + NULL, + 0, + NULL))) + goto failed; if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM, QEMU_PROTOCOL_VERSION, NULL, @@ -776,6 +788,7 @@ doRemoteOpen(virConnectPtr conn, goto failed; if (virNetClientAddProgram(priv->client, priv->remoteProgram) < 0 || + virNetClientAddProgram(priv->client, priv->lxcProgram) < 0 || virNetClientAddProgram(priv->client, priv->qemuProgram) < 0) goto failed; @@ -860,6 +873,7 @@ no_memory: failed: virObjectUnref(priv->remoteProgram); + virObjectUnref(priv->lxcProgram); virObjectUnref(priv->qemuProgram); virNetClientClose(priv->client); virObjectUnref(priv->client); @@ -1024,8 +1038,9 @@ doRemoteClose(virConnectPtr conn, struct private_data *priv) virObjectUnref(priv->client); priv->client = NULL; virObjectUnref(priv->remoteProgram); + virObjectUnref(priv->lxcProgram); virObjectUnref(priv->qemuProgram); - priv->remoteProgram = priv->qemuProgram = NULL; + priv->remoteProgram = priv->qemuProgram = priv->lxcProgram = NULL; /* Free hostname copy */ VIR_FREE(priv->hostname); @@ -5409,6 +5424,8 @@ remoteDomainOpenGraphics(virDomainPtr dom, int rv = -1; remote_domain_open_graphics_args args; struct private_data *priv = dom->conn->privateData; + int fdin[] = { fd }; + size_t fdinlen = ARRAY_CARDINALITY(fdin); remoteDriverLock(priv); @@ -5416,9 +5433,12 @@ remoteDomainOpenGraphics(virDomainPtr dom, args.idx = idx; args.flags = flags; - if (callWithFD(dom->conn, priv, 0, fd, REMOTE_PROC_DOMAIN_OPEN_GRAPHICS, - (xdrproc_t) xdr_remote_domain_open_graphics_args, (char *) &args, - (xdrproc_t) xdr_void, NULL) == -1) + if (callFull(dom->conn, priv, 0, + fdin, fdinlen, + NULL, NULL, + REMOTE_PROC_DOMAIN_OPEN_GRAPHICS, + (xdrproc_t) xdr_remote_domain_open_graphics_args, (char *) &args, + (xdrproc_t) xdr_void, NULL) == -1) goto done; rv = 0; @@ -5523,6 +5543,7 @@ done: } #include "remote_client_bodies.h" +#include "lxc_client_bodies.h" #include "qemu_client_bodies.h" /* @@ -5530,22 +5551,30 @@ done: * send that to the server and wait for reply */ static int -callWithFD(virConnectPtr conn ATTRIBUTE_UNUSED, - struct private_data *priv, - unsigned int flags, - int fd, - int proc_nr, - xdrproc_t args_filter, char *args, - xdrproc_t ret_filter, char *ret) +callFull(virConnectPtr conn ATTRIBUTE_UNUSED, + struct private_data *priv, + unsigned int flags, + int *fdin, + size_t fdinlen, + int **fdout, + size_t *fdoutlen, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) { int rv; - virNetClientProgramPtr prog = flags & REMOTE_CALL_QEMU ? priv->qemuProgram : priv->remoteProgram; + virNetClientProgramPtr prog; int counter = priv->counter++; virNetClientPtr client = priv->client; - int fds[] = { fd }; - size_t nfds = fd == -1 ? 0 : 1; priv->localUses++; + if (flags & REMOTE_CALL_QEMU) + prog = priv->qemuProgram; + else if (flags & REMOTE_CALL_LXC) + prog = priv->lxcProgram; + else + prog = priv->remoteProgram; + /* Unlock, so that if we get any async events/stream data * while processing the RPC, we don't deadlock when our * callbacks for those are invoked @@ -5555,7 +5584,8 @@ callWithFD(virConnectPtr conn ATTRIBUTE_UNUSED, client, counter, proc_nr, - nfds, nfds ? fds : NULL, NULL, NULL, + fdinlen, fdin, + fdoutlen, fdout, args_filter, args, ret_filter, ret); remoteDriverLock(priv); @@ -5572,9 +5602,12 @@ call(virConnectPtr conn, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret) { - return callWithFD(conn, priv, flags, -1, proc_nr, - args_filter, args, - ret_filter, ret); + return callFull(conn, priv, flags, + NULL, 0, + NULL, NULL, + proc_nr, + args_filter, args, + ret_filter, ret); } @@ -5850,6 +5883,40 @@ done: return rv; } + +static int +remoteDomainLxcOpenNamespace(virDomainPtr domain, + int **fdlist, + unsigned int flags) +{ + int rv = -1; + lxc_domain_open_namespace_args args; + struct private_data *priv = domain->conn->privateData; + size_t nfds = 0; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.dom, domain); + args.flags = flags; + + *fdlist = NULL; + + if (callFull(domain->conn, priv, REMOTE_CALL_LXC, + NULL, 0, + fdlist, &nfds, + LXC_PROC_DOMAIN_OPEN_NAMESPACE, + (xdrproc_t) xdr_lxc_domain_open_namespace_args, (char *) &args, + (xdrproc_t) xdr_void, NULL) == -1) + goto done; + + rv = nfds; + +done: + remoteDriverUnlock(priv); + return rv; +} + + static void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -6170,6 +6237,7 @@ static virDriver remote_driver = { .nodeGetMemoryParameters = remoteNodeGetMemoryParameters, /* 0.10.2 */ .nodeGetCPUMap = remoteNodeGetCPUMap, /* 1.0.0 */ .domainFSTrim = remoteDomainFSTrim, /* 1.0.1 */ + .domainLxcOpenNamespace = remoteDomainLxcOpenNamespace, /* 1.0.2 */ }; static virNetworkDriver network_driver = {