[PATCH v2 2/2] multipath-tools: allow using a regular Unix socket for multipathd

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

 



Accessing multipathd's socket from a different network namespace (e.g. from a
container) is impossible with an abstract socket. Add the option to compile
multipathd using a regular Unix socket instead, by compiling with the flag
"use_regular_socket=1". By default, the socket path is /run/multipathd.

While at it, introduce a common helper function for filling in the struct
sockaddr_un correctly, and make sure the socket name is properly
NULL-terminated.

[1] https://github.com/opensvc/multipath-tools/issues/111

Signed-off-by: Martin Wilck <mwilck@xxxxxxxx>
---
 .gitignore                                    |  1 +
 Makefile.inc                                  |  9 +++++--
 README.md                                     |  4 +++
 libmpathcmd/libmpathcmd.version               |  5 ++++
 libmpathcmd/mpath_cmd.c                       | 27 +++++++++++++------
 libmpathcmd/mpath_cmd.h                       |  6 +++++
 libmpathutil/uxsock.c                         | 24 ++++++++++-------
 multipathd/Makefile                           |  7 +++--
 ...multipathd.socket => multipathd.socket.in} |  2 +-
 9 files changed, 61 insertions(+), 24 deletions(-)
 rename multipathd/{multipathd.socket => multipathd.socket.in} (87%)

diff --git a/.gitignore b/.gitignore
index 4548cfb..6a1f6fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ multipathd/multipathd
 multipathd/multipathd.8
 multipathd/multipathc
 multipathd/multipathd.service
+multipathd/multipathd.socket
 mpathpersist/mpathpersist
 mpathpersist/mpathpersist.8
 abi.tar.gz
diff --git a/Makefile.inc b/Makefile.inc
index 949e7b5..104aeaf 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -79,8 +79,11 @@ libudev_incdir	:= $(or $(shell $(PKG_CONFIG) --variable=includedir libudev),/usr
 kernel_incdir	:= /usr/include
 sysdir_bin      := $(sys_execprefix)bin
 
+use_regular_socket   :=
+regular_socket_path  := /run/multipathd.socket
 abstract_socket_path := /org/kernel/linux/storage/multipathd
-mpath_socket         := $(abstract_socket_path)
+mpath_socket         := $(if $(use_regular_socket),$(regular_socket_path),$(abstract_socket_path))
+mpath_socket_systemd := $(if $(use_regular_socket),$(regular_socket_path),@$(abstract_socket_path))
 
 ifeq ($(V),)
 Q		:= @
@@ -118,7 +121,8 @@ CPPFLAGS	:= $(FORTIFY_OPT) $(CPPFLAGS) $(D_URCU_VERSION) \
 		   -DRUNTIME_DIR=\"$(runtimedir)\" -DCONFIG_DIR=\"$(TGTDIR)$(configdir)\" \
 		   -DDEFAULT_CONFIGFILE=\"$(TGTDIR)$(configfile)\" -DSTATE_DIR=\"$(TGTDIR)$(statedir)\" \
 		   -DEXTRAVERSION=\"$(EXTRAVERSION)\" \
-		   -DDEFAULT_SOCKET=\"$(mpath_socket)\" -MMD -MP
+		   -DDEFAULT_SOCKET=\"$(mpath_socket)\" -DUSE_REGULAR_SOCKET=$(if $(use_regular_socket),1,0) \
+		   -MMD -MP
 CFLAGS		:= -std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
 		   -fexceptions
 BIN_CFLAGS	:= -fPIE -DPIE
@@ -171,4 +175,5 @@ NV_VERSION_SCRIPT = $(DEVLIB:%.so=%-nv.version)
 		-e 's:@SYSDIR_BIN@:'$(sysdir_bin)': g' \
 		-e 's:@RUNTIME_DIR@:'$(runtimedir)':g' \
 		-e 's/@MODPROBE_UNIT@/'$(MODPROBE_UNIT)'/g' \
+		-e 's,@MPATH_SOCKET@,'$(mpath_socket_systemd)',g' \
 		$< >$@
diff --git a/README.md b/README.md
index 530caed..f6cf675 100644
--- a/README.md
+++ b/README.md
@@ -121,6 +121,10 @@ The following variables can be passed to the `make` command line:
     stores run-time settings that need persist between reboots, such as known
 	WWIDs, user-friendly names, and persistent reservation keys.
 	The default is `$(etc_prefix)/etc/multipath`.
+ * `use_regular_socket`: if unset (default), use an abstract socket, which is
+   invisible in the file system. Otherwise, if set to 1, use the regular unix socket
+   `/run/multipathd.socket`. Setting this to 1 is necessary in order to
+   communicate with **multipathd** from containers.
  * `READLINE=libedit` or `READLINE=libreadline`: enable command line history
     and TAB completion in the interactive mode *(which is entered with `multipathd -k` or `multipathc`)*.
     The respective development package will be required for building.
diff --git a/libmpathcmd/libmpathcmd.version b/libmpathcmd/libmpathcmd.version
index 81bdb2b..85ed6d2 100644
--- a/libmpathcmd/libmpathcmd.version
+++ b/libmpathcmd/libmpathcmd.version
@@ -27,3 +27,8 @@ LIBMPATHCMD_1.1.0 {
 global:
 	mpath_connect__;
 } LIBMPATHCMD_1.0.0;
+
+LIBMPATHCMD_1.2.0 {
+global:
+	mpath_fill_sockaddr;
+} LIBMPATHCMD_1.1.0;
diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c
index a38e8b6..6e65ffe 100644
--- a/libmpathcmd/mpath_cmd.c
+++ b/libmpathcmd/mpath_cmd.c
@@ -91,6 +91,24 @@ static size_t write_all(int fd, const void *buf, size_t len)
 	return total;
 }
 
+size_t mpath_fill_sockaddr(struct sockaddr_un *addr, const char *name)
+{
+	size_t len;
+
+	addr->sun_family = AF_LOCAL;
+
+#if USE_REGULAR_SOCKET
+	strncpy(&addr->sun_path[0], name, sizeof(addr->sun_path) - 1);
+	len = offsetof(struct sockaddr_un, sun_path) + strlen(name) + 1;
+#else
+	addr->sun_path[0] = '\0';
+	strncpy(&addr->sun_path[1], name, sizeof(addr->sun_path) - 2);
+	len = offsetof(struct sockaddr_un, sun_path) + strlen(name) + 2;
+#endif
+	addr->sun_path[sizeof(addr->sun_path) - 1] = '\0';
+	return len > sizeof(*addr) ? sizeof(*addr) : len;
+}
+
 /*
  * connect to a unix domain socket
  */
@@ -101,14 +119,6 @@ int mpath_connect__(int nonblocking)
 	struct sockaddr_un addr;
 	int flags = 0;
 
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_LOCAL;
-	addr.sun_path[0] = '\0';
-	strncpy(&addr.sun_path[1], DEFAULT_SOCKET, sizeof(addr.sun_path) - 1);
-	len = strlen(DEFAULT_SOCKET) + 1 + sizeof(sa_family_t);
-	if (len > sizeof(struct sockaddr_un))
-		len = sizeof(struct sockaddr_un);
-
 	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
 	if (fd == -1)
 		return -1;
@@ -119,6 +129,7 @@ int mpath_connect__(int nonblocking)
 			(void)fcntl(fd, F_SETFL, flags|O_NONBLOCK);
 	}
 
+	len = mpath_fill_sockaddr(&addr, DEFAULT_SOCKET);
 	if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
 		int err = errno;
 
diff --git a/libmpathcmd/mpath_cmd.h b/libmpathcmd/mpath_cmd.h
index c96fabc..e68607d 100644
--- a/libmpathcmd/mpath_cmd.h
+++ b/libmpathcmd/mpath_cmd.h
@@ -19,6 +19,7 @@
 
 #ifndef MPATH_CMD_H_INCLUDED
 #define MPATH_CMD_H_INCLUDED
+#include <sys/un.h>
 
 /*
  * This should be sufficient for json output for >10000 maps,
@@ -32,6 +33,11 @@ extern "C" {
 
 #define DEFAULT_REPLY_TIMEOUT	4000
 
+/*
+ * DESCRIPTION:
+ *	Helper to fill in the socket name.
+ */
+size_t mpath_fill_sockaddr(struct sockaddr_un *addr, const char *name);
 
 /*
  * DESCRIPTION:
diff --git a/libmpathutil/uxsock.c b/libmpathutil/uxsock.c
index 2135476..3fcc2d9 100644
--- a/libmpathutil/uxsock.c
+++ b/libmpathutil/uxsock.c
@@ -12,6 +12,7 @@
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/un.h>
 #include <poll.h>
 #include <signal.h>
@@ -56,6 +57,11 @@ int ux_socket_listen(const char *name)
 		condlog(3, "using fd %d from sd_listen_fds", fd);
 		return fd;
 	}
+#endif
+#if USE_REGULAR_SOCKET
+	/* This is after the PID check, so unlinking should be fine */
+	if (unlink(name) == -1 && errno != ENOENT)
+		condlog(1, "Failed to unlink %s", name);
 #endif
 	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
 	if (fd == -1) {
@@ -63,21 +69,21 @@ int ux_socket_listen(const char *name)
 		return -1;
 	}
 
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_LOCAL;
-	addr.sun_path[0] = '\0';
-	len = strlen(name) + 1;
-	if (len >= sizeof(addr.sun_path))
-		len = sizeof(addr.sun_path) - 1;
-	memcpy(&addr.sun_path[1], name, len);
-
-	len += sizeof(sa_family_t);
+	len = mpath_fill_sockaddr(&addr, name);
 	if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
 		condlog(3, "Couldn't bind to ux_socket, error %d", errno);
 		close(fd);
 		return -1;
 	}
 
+#if USE_REGULAR_SOCKET
+	/*
+	 * Socket needs to have rw permissions for everone.
+	 * SO_PEERCRED makes sure that only root can modify things.
+	 */
+	if (chmod(name, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1)
+		condlog(3, "failed to set permissions on %s: %s", name, strerror(errno));
+#endif
 	if (listen(fd, 10) == -1) {
 		condlog(3, "Couldn't listen to ux_socket, error %d", errno);
 		close(fd);
diff --git a/multipathd/Makefile b/multipathd/Makefile
index 997b40c..bb9b828 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -41,7 +41,7 @@ ifeq ($(FPIN_SUPPORT),1)
 OBJS += fpin_handlers.o
 endif
 
-all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service
+all : $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket
 
 $(EXEC): $(OBJS) $(multipathdir)/libmultipath.so $(mpathcmddir)/libmpathcmd.so
 	@echo building $@ because of $?
@@ -74,11 +74,10 @@ uninstall:
 	$(Q)$(RM) $(DESTDIR)$(bindir)/$(EXEC) $(DESTDIR)$(bindir)/$(CLI)
 	$(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(EXEC).8
 	$(Q)$(RM) $(DESTDIR)$(mandir)/man8/$(CLI).8
-	$(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).service
-	$(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket
+	$(Q)$(RM) $(DESTDIR)$(unitdir)/$(EXEC).socket $(EXEC).service
 
 clean: dep_clean
-	$(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service
+	$(Q)$(RM) core *.o $(EXEC) $(CLI) $(MANPAGES) $(EXEC).service $(EXEC).socket
 
 include $(wildcard $(OBJS:.o=.d) $(CLI_OBJS:.o=.d))
 
diff --git a/multipathd/multipathd.socket b/multipathd/multipathd.socket.in
similarity index 87%
rename from multipathd/multipathd.socket
rename to multipathd/multipathd.socket.in
index 6a62f5f..c0e86c3 100644
--- a/multipathd/multipathd.socket
+++ b/multipathd/multipathd.socket.in
@@ -7,7 +7,7 @@ ConditionVirtualization=!container
 Before=sockets.target
 
 [Socket]
-ListenStream=@/org/kernel/linux/storage/multipathd
+ListenStream=@MPATH_SOCKET@
 
 [Install]
 # Socket activation for multipathd is disabled by default.
-- 
2.48.1





[Index of Archives]     [DM Crypt]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite Discussion]     [KDE Users]     [Fedora Docs]

  Powered by Linux