diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 3c0e5b6eb1..c0e0f385b4 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -3968,6 +3968,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PassPacketInfo = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly s Timestamping = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b RemoveOnStop = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ss) Listen = [...];
@@ -4523,6 +4525,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
+
+
@@ -5065,6 +5069,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
+
+
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 079cdf0052..015337ff2f 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -253,11 +253,10 @@
ListenFIFO=
- Specifies a file system FIFO to listen on.
- This expects an absolute file system path as argument.
- Behavior otherwise is very similar to the
- ListenDatagram= directive
- above.
+ Specifies a file system FIFO (see fifo7 for
+ details) to listen on. This expects an absolute file system path as argument. Behavior otherwise is
+ very similar to the ListenDatagram= directive above.
@@ -285,12 +284,12 @@
ListenMessageQueue=
- Specifies a POSIX message queue name to listen
- on. This expects a valid message queue name (i.e. beginning
- with /). Behavior otherwise is very similar to the
- ListenFIFO= directive above. On Linux
- message queue descriptors are actually file descriptors and
- can be inherited between processes.
+ Specifies a POSIX message queue name to listen on (see mq_overview7
+ for details). This expects a valid message queue name (i.e. beginning with
+ /). Behavior otherwise is very similar to the ListenFIFO=
+ directive above. On Linux message queue descriptors are actually file descriptors and can be
+ inherited between processes.
@@ -698,10 +697,20 @@
PassPacketInfo=
Takes a boolean value. This controls the IP_PKTINFO,
- IPV6_RECVPKTINFO and NETLINK_PKTINFO socket options, which
- enable reception of additional per-packet metadata as ancillary message, on
- AF_INET, AF_INET6 and AF_UNIX sockets.
- Defaults to .
+ IPV6_RECVPKTINFO, NETLINK_PKTINFO or
+ PACKET_AUXDATA socket options, which enable reception of additional per-packet
+ metadata as ancillary message, on AF_INET, AF_INET6,
+ AF_UNIX and AF_PACKET sockets. Defaults to
+ .
+
+
+
+ Timestamping=
+ Takes one of off, us (alias:
+ usec, µs) or ns (alias:
+ nsec). This controls the SO_TIMESTAMP or
+ SO_TIMESTAMPNS socket options, and enables whether ingress network traffic shall
+ carry timestamping metadata. Defaults to .
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index f2e1148e87..6f57b2a3c4 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -1240,6 +1240,9 @@ int socket_set_recvpktinfo(int fd, int af, bool b) {
case AF_NETLINK:
return setsockopt_int(fd, SOL_NETLINK, NETLINK_PKTINFO, b);
+ case AF_PACKET:
+ return setsockopt_int(fd, SOL_PACKET, PACKET_AUXDATA, b);
+
default:
return -EAFNOSUPPORT;
}
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 07d030adb3..a5d15d80cd 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -20,6 +20,7 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
static BUS_DEFINE_PROPERTY_GET(property_get_fdname, "s", Socket, socket_fdname);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_timestamping, socket_timestamping, SocketTimestamping);
static int property_get_listen(
sd_bus *bus,
@@ -106,6 +107,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PassPacketInfo", "b", bus_property_get_bool, offsetof(Socket, pass_pktinfo), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Timestamping", "s", property_get_timestamping, offsetof(Socket, timestamping), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemoveOnStop", "b", bus_property_get_bool, offsetof(Socket, remove_on_stop), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Symlinks", "as", NULL, offsetof(Socket, symlinks), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -159,6 +161,7 @@ static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(fdname, fdname_is_valid);
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(ifname, ifname_valid);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(ip_tos, "i", int32_t, int, "%" PRIi32, ip_tos_to_string_alloc);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(socket_protocol, "i", int32_t, int, "%" PRIi32, socket_protocol_to_string);
+static BUS_DEFINE_SET_TRANSIENT_PARSE(socket_timestamping, SocketTimestamping, socket_timestamping_from_string_harder);
static int bus_socket_set_transient_property(
Socket *s,
@@ -210,6 +213,9 @@ static int bus_socket_set_transient_property(
if (streq(name, "PassPacketInfo"))
return bus_set_transient_bool(u, name, &s->pass_pktinfo, message, flags, error);
+ if (streq(name, "Timestamping"))
+ return bus_set_transient_socket_timestamping(u, name, &s->timestamping, message, flags, error);
+
if (streq(name, "ReusePort"))
return bus_set_transient_bool(u, name, &s->reuse_port, message, flags, error);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index b5ccf62ae0..063d8ba6b6 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -419,6 +419,7 @@ Socket.Broadcast, config_parse_bool,
Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred)
Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec)
Socket.PassPacketInfo, config_parse_bool, 0, offsetof(Socket, pass_pktinfo)
+Socket.Timestamping, config_parse_socket_timestamping, 0, offsetof(Socket, timestamping)
Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion)
Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port)
Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 60c9a5f03a..0ab64e1708 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -140,6 +140,7 @@ DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t,
DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_status_unit_format, status_unit_format, StatusUnitFormat, "Failed to parse status unit format");
+DEFINE_CONFIG_PARSE_ENUM_FULL(config_parse_socket_timestamping, socket_timestamping_from_string_harder, SocketTimestamping, "Failed to parse timestamping precision");
int config_parse_unit_deps(
const char *unit,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index fa4c1fb1a0..47036145c8 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -136,6 +136,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_crash_chvt);
CONFIG_PARSER_PROTOTYPE(config_parse_timeout_abort);
CONFIG_PARSER_PROTOTYPE(config_parse_swap_priority);
CONFIG_PARSER_PROTOTYPE(config_parse_mount_images);
+CONFIG_PARSER_PROTOTYPE(config_parse_socket_timestamping);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
diff --git a/src/core/socket.c b/src/core/socket.c
index f71fa34300..f045eed5b5 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -629,6 +629,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, socket_fdname(s),
prefix, yes_no(s->selinux_context_from_net));
+ if (s->timestamping != SOCKET_TIMESTAMPING_OFF)
+ fprintf(f,
+ "%sTimestamping: %s\n",
+ prefix, socket_timestamping_to_string(s->timestamping));
+
if (s->control_pid > 0)
fprintf(f,
"%sControl PID: "PID_FMT"\n",
@@ -1051,6 +1056,14 @@ static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) {
log_unit_warning_errno(UNIT(s), r, "Failed to enable packet info socket option: %m");
}
+ if (s->timestamping != SOCKET_TIMESTAMPING_OFF) {
+ r = setsockopt_int(fd, SOL_SOCKET,
+ s->timestamping == SOCKET_TIMESTAMPING_NS ? SO_TIMESTAMPNS : SO_TIMESTAMP,
+ true);
+ if (r < 0)
+ log_unit_warning_errno(UNIT(s), r, "Failed to enable timestamping socket option, ignoring: %m");
+ }
+
if (s->priority >= 0) {
r = setsockopt_int(fd, SOL_SOCKET, SO_PRIORITY, s->priority);
if (r < 0)
@@ -3409,6 +3422,39 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
+static const char* const socket_timestamping_table[_SOCKET_TIMESTAMPING_MAX] = {
+ [SOCKET_TIMESTAMPING_OFF] = "off",
+ [SOCKET_TIMESTAMPING_US] = "us",
+ [SOCKET_TIMESTAMPING_NS] = "ns",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(socket_timestamping, SocketTimestamping);
+
+SocketTimestamping socket_timestamping_from_string_harder(const char *p) {
+ SocketTimestamping t;
+ int r;
+
+ if (!p)
+ return _SOCKET_TIMESTAMPING_INVALID;
+
+ t = socket_timestamping_from_string(p);
+ if (t >= 0)
+ return t;
+
+ /* Let's alternatively support the various other aliases parse_time() accepts for ns and µs here,
+ * too. */
+ if (streq(p, "nsec"))
+ return SOCKET_TIMESTAMPING_NS;
+ if (STR_IN_SET(p, "usec", "µs"))
+ return SOCKET_TIMESTAMPING_US;
+
+ r = parse_boolean(p);
+ if (r < 0)
+ return _SOCKET_TIMESTAMPING_INVALID;
+
+ return r ? SOCKET_TIMESTAMPING_NS : SOCKET_TIMESTAMPING_OFF; /* If boolean yes, default to ns accuracy */
+}
+
const UnitVTable socket_vtable = {
.object_size = sizeof(Socket),
.exec_context_offset = offsetof(Socket, exec_context),
diff --git a/src/core/socket.h b/src/core/socket.h
index cf475e2638..90839de9fa 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -58,6 +58,14 @@ typedef struct SocketPort {
LIST_FIELDS(struct SocketPort, port);
} SocketPort;
+typedef enum SocketTimestamping {
+ SOCKET_TIMESTAMPING_OFF,
+ SOCKET_TIMESTAMPING_US, /* SO_TIMESTAMP */
+ SOCKET_TIMESTAMPING_NS, /* SO_TIMESTAMPNS */
+ _SOCKET_TIMESTAMPING_MAX,
+ _SOCKET_TIMESTAMPING_INVALID = -1,
+} SocketTimestamping;
+
struct Socket {
Unit meta;
@@ -123,6 +131,7 @@ struct Socket {
bool pass_cred;
bool pass_sec;
bool pass_pktinfo;
+ SocketTimestamping timestamping;
/* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
SocketAddressBindIPv6Only bind_ipv6_only;
@@ -182,4 +191,8 @@ SocketResult socket_result_from_string(const char *s) _pure_;
const char* socket_port_type_to_string(SocketPort *p) _pure_;
SocketType socket_port_type_from_string(const char *p) _pure_;
+const char* socket_timestamping_to_string(SocketTimestamping p) _const_;
+SocketTimestamping socket_timestamping_from_string(const char *p) _pure_;
+SocketTimestamping socket_timestamping_from_string_harder(const char *p) _pure_;
+
DEFINE_CAST(SOCKET, Socket);
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index f2b867da3d..fed81161e0 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -483,13 +483,11 @@ int server_open_native_socket(Server *s, const char *native_socket) {
if (r < 0)
return log_error_errno(r, "SO_PASSCRED failed: %m");
-#if HAVE_SELINUX
if (mac_selinux_use()) {
r = setsockopt_int(s->native_fd, SOL_SOCKET, SO_PASSSEC, true);
if (r < 0)
log_warning_errno(r, "SO_PASSSEC failed: %m");
}
-#endif
r = setsockopt_int(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, true);
if (r < 0)
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 0da7dcfcf5..91ea41fa78 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -70,9 +70,8 @@ static void forward_syslog_iovec(
msghdr.msg_controllen = cmsg->cmsg_len;
}
- /* Forward the syslog message we received via /dev/log to
- * /run/systemd/syslog. Unfortunately we currently can't set
- * the SO_TIMESTAMP auxiliary data, and hence we don't. */
+ /* Forward the syslog message we received via /dev/log to /run/systemd/syslog. Unfortunately we
+ * currently can't set the SO_TIMESTAMP auxiliary data, and hence we don't. */
if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
return;
@@ -484,13 +483,11 @@ int server_open_syslog_socket(Server *s, const char *syslog_socket) {
if (r < 0)
return log_error_errno(r, "SO_PASSCRED failed: %m");
-#if HAVE_SELINUX
if (mac_selinux_use()) {
r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, true);
if (r < 0)
log_warning_errno(r, "SO_PASSSEC failed: %m");
}
-#endif
r = setsockopt_int(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, true);
if (r < 0)
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 89e0c5bb95..79c2e0cf19 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2037,7 +2037,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
"BindIPv6Only",
"FileDescriptorName",
"SocketUser",
- "SocketGroup"))
+ "SocketGroup",
+ "Timestamping"))
return bus_append_string(m, field, eq);
if (streq(field, "Symlinks"))
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 2514dcbf48..d2391d43bb 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -193,7 +193,7 @@ typedef enum Disabled {
return 0; \
}
-#define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
+#define DEFINE_CONFIG_PARSE_ENUM_FULL(function, from_string, type, msg) \
CONFIG_PARSER_PROTOTYPE(function) { \
type *i = data, x; \
\
@@ -202,7 +202,7 @@ typedef enum Disabled {
assert(rvalue); \
assert(data); \
\
- x = name##_from_string(rvalue); \
+ x = from_string(rvalue); \
if (x < 0) { \
log_syntax(unit, LOG_WARNING, filename, line, 0, \
msg ", ignoring: %s", rvalue); \
@@ -213,6 +213,9 @@ typedef enum Disabled {
return 0; \
}
+#define DEFINE_CONFIG_PARSE_ENUM(function, name, type, msg) \
+ DEFINE_CONFIG_PARSE_ENUM_FULL(function, name##_from_string, type, msg)
+
#define DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(function, name, type, default_value, msg) \
CONFIG_PARSER_PROTOTYPE(function) { \
type *i = data, x; \
diff --git a/units/systemd-journald-dev-log.socket b/units/systemd-journald-dev-log.socket
index 80ad6ac845..7cec55440d 100644
--- a/units/systemd-journald-dev-log.socket
+++ b/units/systemd-journald-dev-log.socket
@@ -19,12 +19,13 @@ Before=sockets.target
IgnoreOnIsolate=yes
[Socket]
-Service=systemd-journald.service
ListenDatagram=/run/systemd/journal/dev-log
-Symlinks=/dev/log
-SocketMode=0666
PassCredentials=yes
PassSecurity=yes
+Service=systemd-journald.service
+SocketMode=0666
+Symlinks=/dev/log
+Timestamping=us
# Increase both the send and receive buffer, so that things don't
# block early. Note that journald internally uses the this socket both
diff --git a/units/systemd-journald.socket b/units/systemd-journald.socket
index c95ae5ab64..95d5f21964 100644
--- a/units/systemd-journald.socket
+++ b/units/systemd-journald.socket
@@ -19,10 +19,11 @@ Before=sockets.target
IgnoreOnIsolate=yes
[Socket]
-ListenStream=/run/systemd/journal/stdout
ListenDatagram=/run/systemd/journal/socket
-SocketMode=0666
+ListenStream=/run/systemd/journal/stdout
PassCredentials=yes
PassSecurity=yes
ReceiveBuffer=8M
Service=systemd-journald.service
+SocketMode=0666
+Timestamping=us