@@ -709,6 +709,18 @@ punix:<file>
<file> to mimic the behavior of a Unix domain socket. The ACLs of the named
pipe include LocalSystem, Administrators, and Creator Owner.
+pfd:<fd>
+ Listen on a pre-opened file descriptor <fd>. The file descriptor must
+ refer to a bound, listening Unix domain stream socket. This is intended
+ for use with systemd socket activation, where systemd opens the socket
+ and passes it to the service.
+
+ For security, ``pfd:`` may only be specified on the command line
+ (``--remote=pfd:<fd>``). It is rejected if added at runtime via
+ ``ovsdb-server/add-remote`` or through the database.
+
+ This connection method is not supported on Windows.
+
All IP-based connection methods accept IPv4 and IPv6 addresses. To specify an
IPv6 address, wrap it in square brackets, e.g. ``ssl:[::1]:6640``. Passive
IP-based connection methods by default listen for IPv4 connections only; use
@@ -195,6 +195,7 @@ extern const struct pstream_class ptcp_pstream_class;
#ifndef _WIN32
extern const struct stream_class unix_stream_class;
extern const struct pstream_class punix_pstream_class;
+extern const struct pstream_class pfd_pstream_class;
#else
extern const struct stream_class windows_stream_class;
extern const struct pstream_class pwindows_pstream_class;
@@ -136,3 +136,55 @@ const struct pstream_class punix_pstream_class = {
NULL,
};
+/* Pre-opened file descriptor passive stream.
+ *
+ * Used for systemd socket activation: systemd opens and binds the socket,
+ * then passes it to the service as a pre-opened file descriptor. */
+
+static int
+pfd_open(const char *name, char *suffix,
+ struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
+{
+ long fd;
+
+ if (!str_to_long(suffix, 10, &fd) || fd < 0) {
+ VLOG_ERR("%s: bad file descriptor", name);
+ return EINVAL;
+ }
+
+ /* Verify it is a listening stream socket. */
+ int sock_type;
+ socklen_t len = sizeof sock_type;
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &len)) {
+ VLOG_ERR("%s: not a socket (%s)", name, ovs_strerror(errno));
+ return errno;
+ }
+ if (sock_type != SOCK_STREAM) {
+ VLOG_ERR("%s: not a stream socket (type %d)", name, sock_type);
+ return EINVAL;
+ }
+ int listening;
+ len = sizeof listening;
+ if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &len)
+ || !listening) {
+ VLOG_ERR("%s: not a listening socket", name);
+ return EINVAL;
+ }
+
+ int error = set_nonblocking(fd);
+ if (error) {
+ return error;
+ }
+
+ return new_fd_pstream(xstrdup(name), fd, punix_accept, NULL, pstreamp);
+}
+
+const struct pstream_class pfd_pstream_class = {
+ "pfd",
+ false,
+ pfd_open,
+ NULL,
+ NULL,
+ NULL,
+};
+
@@ -69,6 +69,7 @@ static const struct pstream_class *pstream_classes[] = {
&ptcp_pstream_class,
#ifndef _WIN32
&punix_pstream_class,
+ &pfd_pstream_class,
#else
&pwindows_pstream_class,
#endif
@@ -147,6 +148,10 @@ stream_usage(const char *name, bool active, bool passive,
#endif
printf(" punix:FILE "
"listen on Unix domain socket FILE\n");
+#ifndef _WIN32
+ printf(" pfd:FD "
+ "listen on pre-opened file descriptor FD\n");
+#endif
}
#ifdef HAVE_OPENSSL
@@ -1425,6 +1425,12 @@ add_manager_options(struct shash *remotes, const struct ovsdb_row *row)
return;
}
+ if (!strncmp("pfd:", target, 4)) {
+ VLOG_WARN_RL(&rl, "pfd: remotes can only be specified on the "
+ "command line; ignoring \"%s\" from database", target);
+ return;
+ }
+
options = add_remote(remotes, target, NULL);
if (ovsdb_util_read_integer_column(row, "max_backoff", &max_backoff)) {
options->rpc.max_backoff = max_backoff;
@@ -1485,7 +1491,16 @@ query_db_remotes(const char *name, const struct shash *all_dbs,
datum = &row->fields[column->index];
for (i = 0; i < datum->n; i++) {
- add_remote(remotes, json_string(datum->keys[i].s), NULL);
+ const char *t = json_string(datum->keys[i].s);
+ if (!strncmp("pfd:", t, 4)) {
+ static struct vlog_rate_limit pfd_rl
+ = VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&pfd_rl, "pfd: remotes can only be "
+ "specified on the command line; ignoring "
+ "\"%s\" from database", t);
+ continue;
+ }
+ add_remote(remotes, t, NULL);
}
}
} else if (column->type.key.type == OVSDB_TYPE_UUID
@@ -2291,6 +2306,12 @@ ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
return;
}
+ if (!strncmp("pfd:", remote, 4)) {
+ unixctl_command_reply_error(conn,
+ "pfd: remotes can only be specified on the command line");
+ return;
+ }
+
retval = (strncmp("db:", remote, 3)
? NULL
: parse_db_column(config->all_dbs, remote,