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,
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),
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,
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);
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)
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,
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);
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",
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)
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),
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;
bool pass_cred;
bool pass_sec;
bool pass_pktinfo;
+ SocketTimestamping timestamping;
/* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
SocketAddressBindIPv6Only bind_ipv6_only;
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);
"BindIPv6Only",
"FileDescriptorName",
"SocketUser",
- "SocketGroup"))
+ "SocketGroup",
+ "Timestamping"))
return bus_append_string(m, field, eq);
if (streq(field, "Symlinks"))