@@ -1,5 +1,6 @@
etc/init.d/ibacm
lib/systemd/system/ibacm.service
+lib/systemd/system/ibacm.socket
usr/bin/ib_acme
usr/include/infiniband/acm.h
usr/include/infiniband/acm_prov.h
@@ -16,6 +16,7 @@ rdma_sbin_executable(ibacm
target_link_libraries(ibacm LINK_PRIVATE
ibverbs
ibumad
+ ${SYSTEMD_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${CMAKE_DL_LIBS}
)
@@ -68,3 +69,8 @@ rdma_subst_install(FILES "ibacm.service.in"
DESTINATION "${CMAKE_INSTALL_SYSTEMD_SERVICEDIR}"
RENAME ibacm.service
PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
+
+install(FILES "ibacm.socket"
+ DESTINATION "${CMAKE_INSTALL_SYSTEMD_SERVICEDIR}"
+ RENAME ibacm.socket
+ PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
@@ -2,9 +2,11 @@
Description=InfiniBand Address Cache Manager Daemon
Documentation=man:ibacm file:@CMAKE_INSTALL_SYSCONFDIR@/rdma/ibacm_opts.cfg
After=opensm.service
+Wants=ibacm.socket
[Service]
-ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/ibacm -P
+ExecStart=@CMAKE_INSTALL_FULL_SBINDIR@/ibacm --systemd
[Install]
+Also=ibacm.socket
WantedBy=network.target
new file mode 100644
@@ -0,0 +1,10 @@
+[Unit]
+Description=Socket for InfiniBand Address Cache Manager Daemon
+Documentation=man:ibacm
+
+[Socket]
+ListenStream=6125
+BindToDevice=lo
+
+[Install]
+WantedBy=sockets.target
@@ -50,6 +50,10 @@ address configuration file
.TP
\-O option_file
option configuration file
+.TP
+\--systemd
+Enable systemd integration. This includes optional socket activation of the daemon's
+listening socket.
.SH "QUICK START GUIDE"
1. Prerequisites: libibverbs and libibumad must be installed.
The IB stack should be running with IPoIB configured.
@@ -59,6 +59,8 @@
#include <rdma/ib_user_sa.h>
#include <poll.h>
#include <inttypes.h>
+#include <getopt.h>
+#include <systemd/sd-daemon.h>
#include <ccan/list.h>
#include <util/util.h>
#include "acm_mad.h"
@@ -599,6 +601,35 @@ static int acm_listen(void)
return 0;
}
+/* Retrieve the listening socket from systemd. */
+static int acm_listen_systemd(void)
+{
+ int rc = sd_listen_fds(1);
+ if (rc == 0) {
+ /* We are in systemd mode but no FDs were passed? Fall back to
+ * normal mode
+ */
+ return acm_listen();
+ }
+ if (rc == -1) {
+ fprintf(stderr, "sd_listen_fds failed %d\n", rc);
+ return rc;
+ }
+
+ if (rc != 1) {
+ fprintf(stderr, "sd_listen_fds returned %d fds, expected 1\n", rc);
+ return -1;
+ }
+
+ if (!sd_is_socket(SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 1)) {
+ fprintf(stderr, "sd_listen_fds socket is not a SOCK_STREAM listening socket\n");
+ return -1;
+ }
+
+ listen_socket = SD_LISTEN_FDS_START;
+ return 0;
+}
+
static void acm_disconnect_client(struct acmc_client *client)
{
pthread_mutex_lock(&client->lock);
@@ -1669,7 +1700,7 @@ static int acm_init_nl(void)
return 0;
}
-static void acm_server(void)
+static void acm_server(bool systemd)
{
fd_set readfds;
int i, n, ret;
@@ -1677,7 +1708,10 @@ static void acm_server(void)
acm_log(0, "started\n");
acm_init_server();
- ret = acm_listen();
+ if (systemd)
+ ret = acm_listen_systemd();
+ else
+ ret = acm_listen();
if (ret) {
acm_log(0, "ERROR - server listen failed\n");
return;
@@ -2949,8 +2983,15 @@ static void show_usage(char *program)
int main(int argc, char **argv)
{
int i, op, as_daemon = 1;
+ bool systemd = false;
+
+ static const struct option long_opts[] = {
+ {"systemd", 0, NULL, 's'},
+ {}
+ };
- while ((op = getopt(argc, argv, "DPA:O:")) != -1) {
+ while ((op = getopt_long(argc, argv, "DPA:O:", long_opts, NULL)) !=
+ -1) {
switch (op) {
case 'D':
/* option no longer required */
@@ -2964,13 +3005,16 @@ int main(int argc, char **argv)
case 'O':
opts_file = optarg;
break;
+ case 's':
+ systemd = true;
+ break;
default:
show_usage(argv[0]);
exit(1);
}
}
- if (as_daemon) {
+ if (as_daemon && !systemd) {
if (daemon(0, 0))
return EXIT_FAILURE;
}
@@ -3013,7 +3057,7 @@ int main(int argc, char **argv)
}
acm_activate_devices();
acm_log(1, "starting server\n");
- acm_server();
+ acm_server(systemd);
acm_log(0, "shutting down\n");
if (client_array[NL_CLIENT_INDEX].sock != -1)
@@ -389,6 +389,7 @@ rm -rf %{buildroot}/%{_sbindir}/srp_daemon.sh
%{_mandir}/man7/ibacm.*
%{_mandir}/man7/ibacm_prov.*
%{_unitdir}/ibacm.service
+%{_unitdir}/ibacm.socket
%dir %{_libdir}/ibacm
%{_libdir}/ibacm/*
%doc %{_docdir}/%{name}-%{version}/ibacm.md
This lets systemd create the socket (to the admin's specifications) and starts ibacm when something connects to it. We are using this to improve boot ordering by ensuring that any rdma_cm clients that would use ibacm block until ibacm is started up properly. A user could also use this to demand start ibacm, but that means it would not plug into kernel RMDA local services for caching. For security, the socket will be created on the lo interface by default. The admin can change this back to the old daemon behavior with a systemd drop in. Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> --- debian/ibacm.install | 1 + ibacm/CMakeLists.txt | 6 ++++++ ibacm/ibacm.service.in | 4 +++- ibacm/ibacm.socket | 10 ++++++++++ ibacm/man/ibacm.1 | 4 ++++ ibacm/src/acm.c | 54 +++++++++++++++++++++++++++++++++++++++++++++----- redhat/rdma-core.spec | 1 + 7 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 ibacm/ibacm.socket