]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add Timestamping= option for socket units
authorLennart Poettering <lennart@poettering.net>
Mon, 26 Oct 2020 16:39:14 +0000 (17:39 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 27 Oct 2020 13:12:39 +0000 (14:12 +0100)
This adds a way to control SO_TIMESTAMP/SO_TIMESTAMPNS socket options
for sockets PID 1 binds to.

This is useful in journald so that we get proper timestamps even for
ingress log messages that are submitted before journald is running.

We recently turned on packet info metadata from PID 1 for these sockets,
but the timestamping info was still missing. Let's correct that.

src/core/dbus-socket.c
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/socket.c
src/core/socket.h
src/shared/bus-unit-util.c

index 07d030adb3a6235f433ff6673d9f74085bb8e648..a5d15d80cd50df4001237f2c6dc5b1bcfa0a31ea 100644 (file)
@@ -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);
 
index b5ccf62ae09124bc4dbc41888dddc6d8a5447d18..063d8ba6b62fe801fe0a6c65ef09c23dfcfaa38d 100644 (file)
@@ -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)
index 60c9a5f03a94fed093a1f1521c2eb45add4b9ff5..0ab64e17082c909139a4d182f8c7bae3e71d6a32 100644 (file)
@@ -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,
index fa4c1fb1a01855fea20d2e09e8339a14802db748..47036145c80cd89c0cd95b2ea6929ed608f54535 100644 (file)
@@ -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);
index f71fa34300b8a3b5a86e44755d2be29fdc46120a..f045eed5b553482908d483e8596d1cf7c2435b51 100644 (file)
@@ -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),
index cf475e26389fe079e700a9a4c6061c6c5920ac6e..90839de9fabce09a7fdc559e10727ff61930e253 100644 (file)
@@ -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);
index 89e0c5bb95e2d173d0abb3614fbc87bc0d0d814b..79c2e0cf1991257b3d568dd9c72b6bdf83b17c88 100644 (file)
@@ -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"))