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

[Xen-devel] [PATCH v4 05/15] oxenstored: add support for systemd active sockets



From: "Luis R. Rodriguez" <mcgrof@xxxxxxxx>

This adds systemd socket activation support for the Ocaml xenstored.
Ocaml lacks systemd library support so we provide our own C helpers
as is done with other functionality lacking on Ocaml.

Active sockets enables oxenstored to be loaded only if required by a system
onto which Xen is installed on. Socket activation is handled by
systemd, once a port for a service which claims a socket is used
systemd will start the required services for it, on demand. For more
details on socket activation refer to Lennart's socket-activation
post regarding this [0].

An important different with socket activation is that systemd will set
FD_CLOEXEC for us on the socket before giving it to us, Ocaml gets
support for [1] Unix.set_cloexec but only as of 4.00.1+dev which isn't
yet widely available on distributions.

Right now this code adds a no-op for this functionality, leaving the
enablement to be done later once systemd is properly hooked into
the build system. The socket activation is ordered in aligment with
the socket activation order passed on to systemd.

[0] http://0pointer.de/blog/projects/socket-activation2.html
[1] http://caml.inria.fr/mantis/view.php?id=5569

Cc: David Scott <dave.scott@xxxxxxxxxxxxx>
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
Cc: Vincent Hanquez <Vincent.Hanquez@xxxxxxxxxxxxx>
Signed-off-by: Luis R. Rodriguez <mcgrof@xxxxxxxx>
---
 tools/ocaml/xenstored/Makefile        |   8 +-
 tools/ocaml/xenstored/systemd.ml      |  16 ++++
 tools/ocaml/xenstored/systemd.mli     |  21 +++++
 tools/ocaml/xenstored/systemd_stubs.c | 166 ++++++++++++++++++++++++++++++++++
 tools/ocaml/xenstored/utils.ml        |  21 +++--
 5 files changed, 224 insertions(+), 8 deletions(-)
 create mode 100644 tools/ocaml/xenstored/systemd.ml
 create mode 100644 tools/ocaml/xenstored/systemd.mli
 create mode 100644 tools/ocaml/xenstored/systemd_stubs.c

diff --git a/tools/ocaml/xenstored/Makefile b/tools/ocaml/xenstored/Makefile
index 7fa8f53..382a813 100644
--- a/tools/ocaml/xenstored/Makefile
+++ b/tools/ocaml/xenstored/Makefile
@@ -15,6 +15,11 @@ syslog_OBJS = syslog
 syslog_C_OBJS = syslog_stubs
 OCAML_LIBRARY = syslog
 
+LIBS += systemd.cma systemd.cmxa
+systemd_OBJS = systemd
+systemd_C_OBJS = systemd_stubs
+OCAML_LIBRARY += systemd
+
 OBJS = define \
        stdext \
        trie \
@@ -36,11 +41,12 @@ OBJS = define \
        process \
        xenstored
 
-INTF = symbol.cmi trie.cmi syslog.cmi
+INTF = symbol.cmi trie.cmi syslog.cmi systemd.cmi
 
 XENSTOREDLIBS = \
        unix.cmxa \
        -ccopt -L -ccopt . syslog.cmxa \
+       -ccopt -L -ccopt . systemd.cmxa \
        -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/mmap 
$(OCAML_TOPLEVEL)/libs/mmap/xenmmap.cmxa \
        -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/eventchn 
$(OCAML_TOPLEVEL)/libs/eventchn/xeneventchn.cmxa \
        -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xc 
$(OCAML_TOPLEVEL)/libs/xc/xenctrl.cmxa \
diff --git a/tools/ocaml/xenstored/systemd.ml b/tools/ocaml/xenstored/systemd.ml
new file mode 100644
index 0000000..cace794
--- /dev/null
+++ b/tools/ocaml/xenstored/systemd.ml
@@ -0,0 +1,16 @@
+(*
+ * Copyright (C) 2014 Luis R. Rodriguez <mcgrof@xxxxxxxx>
+ *
+ * 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.
+ *)
+
+external sd_listen_fds: string -> Unix.file_descr = "ocaml_sd_listen_fds"
+external sd_active_socket_required: unit -> int = 
"ocaml_sd_active_socket_required"
diff --git a/tools/ocaml/xenstored/systemd.mli 
b/tools/ocaml/xenstored/systemd.mli
new file mode 100644
index 0000000..a65ea5e
--- /dev/null
+++ b/tools/ocaml/xenstored/systemd.mli
@@ -0,0 +1,21 @@
+(*
+ * Copyright (C) 2014 Luis R. Rodriguez <mcgrof@xxxxxxxx>
+ *
+ * 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.
+ *)
+
+(** Calls the C library sd_listen_fds() function for us. Although
+ *  the library doesn't accept argument we send one over to help
+ *  us do sanity checks on the expected sockets *)
+val sd_listen_fds: string -> Unix.file_descr
+
+(** Tells us whether or not systemd support was compiled in *)
+val sd_active_socket_required: unit -> int
diff --git a/tools/ocaml/xenstored/systemd_stubs.c 
b/tools/ocaml/xenstored/systemd_stubs.c
new file mode 100644
index 0000000..ded9542
--- /dev/null
+++ b/tools/ocaml/xenstored/systemd_stubs.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 Luis R. Rodriguez <mcgrof@xxxxxxxx>
+ *
+ * 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 <string.h>
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+#include <caml/custom.h>
+#include <caml/signals.h>
+#include <caml/fail.h>
+#include <config.h>
+#if defined(HAVE_SYSTEMD)
+#include <sys/socket.h>
+#include <systemd/sd-daemon.h>
+#endif
+
+#if defined(HAVE_SYSTEMD)
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
+#endif
+
+/* Conforms to what we should send sd_is_socket_unix() */
+struct xen_systemd_active_socket {
+       int fd;
+       int type;
+       int listening;
+       const char *path;
+       size_t length;
+};
+
+/*
+ * We list stdin, stdout and stderr simply for documentation purposes
+ * and to help our array size fit the number of expected sockets we
+ * as sd_listen_fds() will return 5 for example if you set the socket
+ * service with 2 sockets.
+ */
+static struct xen_systemd_active_socket xenstore_active_sockets[] = {
+       {
+               .fd = SD_LISTEN_FDS_START -3,
+               .type = 0,
+               .listening = 0,
+               .path = "stdin",
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START - 2,
+               .type = 0,
+               .listening = 0,
+               .path = "stderr",
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START - 1,
+               .type = 0,
+               .listening = 0,
+               .path = "stderr",
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START,
+               .type = SOCK_STREAM,
+               .listening = 0,
+               .path = "/var/run/xenstored/socket",
+               .length = 0,
+       },
+       {
+               .fd = SD_LISTEN_FDS_START + 1,
+               .type = SOCK_STREAM,
+               .listening = 0,
+               .path = "/var/run/xenstored/socket_ro",
+               .length = 0,
+       },
+};
+
+static struct xen_systemd_active_socket *get_xen_active_socket(const char 
*connect_to)
+{
+       unsigned int i;
+
+       for (i=0; i<ARRAY_SIZE(xenstore_active_sockets); i++) {
+               if (!strcmp(connect_to, xenstore_active_sockets[i].path)) {
+                       if (!xenstore_active_sockets[i].type)
+                               return NULL;
+                       return &xenstore_active_sockets[i];
+               }
+       }
+
+       return NULL;
+}
+
+CAMLprim value ocaml_sd_listen_fds(value connect_to)
+{
+       CAMLparam1(connect_to);
+       CAMLlocal1(sock_ret);
+       int n, r;
+       struct xen_systemd_active_socket *active_socket;
+
+       active_socket = get_xen_active_socket((const char *) 
String_val(connect_to));
+       if (!active_socket)
+               caml_failwith("ocaml_sd_listen_fds() got invalid request");
+
+       n = sd_listen_fds(0);
+       if (n <= 0)
+               caml_failwith("ocaml_sd_listen_fds() failed");
+       else if (n >= (ARRAY_SIZE(xenstore_active_sockets)))
+               caml_failwith("ocaml_sd_listen_fds() got unexpected request");
+
+       r = sd_is_socket_unix(active_socket->fd,
+                             active_socket->type,
+                             active_socket->listening,
+                             active_socket->path,
+                             active_socket->length);
+       if (r < 0)
+               caml_failwith("ocaml_sd_listen_fds() mismatch on socket");
+
+       sock_ret = Val_int(active_socket->fd);
+
+       CAMLreturn(sock_ret);
+}
+
+/*
+ * If xenstored was built to depend on systemd libraries
+ * we assume you want all the bells and whistles with
+ * systemd.
+ */
+CAMLprim value ocaml_sd_active_socket_required(void)
+{
+       CAMLparam0();
+       CAMLlocal1(ret);
+
+       ret = Val_int(1);
+
+       CAMLreturn(ret);
+}
+#else
+CAMLprim value ocaml_sd_listen_fds(value connect_to)
+{
+       CAMLparam1(connect_to);
+       CAMLlocal1(sock_ret);
+
+       sock_ret = Val_int(-1);
+
+       CAMLreturn(sock_ret);
+}
+
+CAMLprim value ocaml_sd_active_socket_required(void)
+{
+       CAMLparam0();
+       CAMLlocal1(ret);
+
+       ret = Val_int(0);
+
+       CAMLreturn(ret);
+}
+#endif
diff --git a/tools/ocaml/xenstored/utils.ml b/tools/ocaml/xenstored/utils.ml
index 68b70c5..d3d2e31 100644
--- a/tools/ocaml/xenstored/utils.ml
+++ b/tools/ocaml/xenstored/utils.ml
@@ -73,14 +73,21 @@ let trim_path path =
 let join_by_null ls = String.concat "\000" ls
 
 (* unix utils *)
+let create_regular_unix_socket name =
+        Unixext.unlink_safe name;
+        Unixext.mkdir_rec (Filename.dirname name) 0o700;
+        let sockaddr = Unix.ADDR_UNIX(name) in
+        let sock = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in
+        Unix.bind sock sockaddr;
+        Unix.listen sock 1;
+        sock
+
 let create_unix_socket name =
-       Unixext.unlink_safe name;
-       Unixext.mkdir_rec (Filename.dirname name) 0o700;
-       let sockaddr = Unix.ADDR_UNIX(name) in
-       let sock = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in
-       Unix.bind sock sockaddr;
-       Unix.listen sock 1;
-       sock
+        let active_sockets = Systemd.sd_active_socket_required() in
+        if active_sockets = 1 then
+                Systemd.sd_listen_fds name
+        else
+                create_regular_unix_socket name
 
 let read_file_single_integer filename =
        let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0o640 in
-- 
1.9.0


_______________________________________________
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®.