diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 4ca0583d65..47d4b4828b 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -4735,6 +4735,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
readonly t TriggerLimitIntervalUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u TriggerLimitBurst = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly t PollLimitIntervalUSec = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly u PollLimitBurst = ...;
readonly u UID = ...;
readonly u GID = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
@@ -5969,6 +5973,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
+
+
+
+
@@ -6505,6 +6513,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
+ PollLimitIntervalUSec/PollLimitBurst properties configure the
+ polling limit for the socket unit. Expects a time in µs, resp. an unsigned integer. If either is set to
+ zero the limiting feature is turned off.
+
Properties
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 09a3a9502b..04552b7c60 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -129,6 +129,8 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("PollLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, poll_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("PollLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, poll_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -248,6 +250,9 @@ static int bus_socket_set_transient_property(
if (streq(name, "TriggerLimitBurst"))
return bus_set_transient_unsigned(u, name, &s->trigger_limit.burst, message, flags, error);
+ if (streq(name, "PollLimitBurst"))
+ return bus_set_transient_unsigned(u, name, &s->poll_limit_burst, message, flags, error);
+
if (streq(name, "SocketMode"))
return bus_set_transient_mode_t(u, name, &s->socket_mode, message, flags, error);
@@ -275,6 +280,9 @@ static int bus_socket_set_transient_property(
if (streq(name, "TriggerLimitIntervalUSec"))
return bus_set_transient_usec(u, name, &s->trigger_limit.interval, message, flags, error);
+ if (streq(name, "PollLimitIntervalUSec"))
+ return bus_set_transient_usec(u, name, &s->poll_limit_interval, message, flags, error);
+
if (streq(name, "SmackLabel"))
return bus_set_transient_string(u, name, &s->smack, message, flags, error);
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index b66adf2811..0d1ee9c231 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -507,6 +507,8 @@ Socket.FileDescriptorName, config_parse_fdname,
Socket.Service, config_parse_socket_service, 0, 0
Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval)
Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst)
+Socket.PollLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, poll_limit_interval)
+Socket.PollLimitBurst, config_parse_unsigned, 0, offsetof(Socket, poll_limit_burst)
{% if ENABLE_SMACK %}
Socket.SmackLabel, config_parse_unit_string_printf, 0, offsetof(Socket, smack)
Socket.SmackLabelIPIn, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_in)
diff --git a/src/core/socket.c b/src/core/socket.c
index 9e7809721a..3e25cc8d6e 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -102,6 +102,9 @@ static void socket_init(Unit *u) {
s->trigger_limit.interval = USEC_INFINITY;
s->trigger_limit.burst = UINT_MAX;
+
+ s->poll_limit_interval = USEC_INFINITY;
+ s->poll_limit_burst = UINT_MAX;
}
static void socket_unwatch_control_pid(Socket *s) {
@@ -307,17 +310,20 @@ static int socket_add_extras(Socket *s) {
* off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to
* process whatever is queued in one go, and thus should normally never have to be started frequently. This is
* different for Accept=yes where each connection is processed by a new service instance, and thus frequent
- * service starts are typical. */
+ * service starts are typical.
+ *
+ * For the poll limit we follow a similar rule, but use 3/4th of the trigger limit parameters, to
+ * trigger this earlier. */
if (s->trigger_limit.interval == USEC_INFINITY)
s->trigger_limit.interval = 2 * USEC_PER_SEC;
+ if (s->trigger_limit.burst == UINT_MAX)
+ s->trigger_limit.burst = s->accept ? 200 : 20;
- if (s->trigger_limit.burst == UINT_MAX) {
- if (s->accept)
- s->trigger_limit.burst = 200;
- else
- s->trigger_limit.burst = 20;
- }
+ if (s->poll_limit_interval == USEC_INFINITY)
+ s->poll_limit_interval = 2 * USEC_PER_SEC;
+ if (s->poll_limit_burst == UINT_MAX)
+ s->poll_limit_burst = s->accept ? 150 : 15;
if (have_non_accept_socket(s)) {
@@ -767,9 +773,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f,
"%sTriggerLimitIntervalSec: %s\n"
- "%sTriggerLimitBurst: %u\n",
+ "%sTriggerLimitBurst: %u\n"
+ "%sPollLimitIntervalSec: %s\n"
+ "%sPollLimitBurst: %u\n",
prefix, FORMAT_TIMESPAN(s->trigger_limit.interval, USEC_PER_SEC),
- prefix, s->trigger_limit.burst);
+ prefix, s->trigger_limit.burst,
+ prefix, FORMAT_TIMESPAN(s->poll_limit_interval, USEC_PER_SEC),
+ prefix, s->poll_limit_burst);
str = ip_protocol_to_name(s->socket_protocol);
if (str)
@@ -1761,6 +1771,10 @@ static int socket_watch_fds(Socket *s) {
(void) sd_event_source_set_description(p->event_source, "socket-port-io");
}
+
+ r = sd_event_source_set_ratelimit(p->event_source, s->poll_limit_interval, s->poll_limit_burst);
+ if (r < 0)
+ log_unit_debug_errno(UNIT(s), r, "Failed to set poll limit on I/O event source, ignoring: %m");
}
return 0;
diff --git a/src/core/socket.h b/src/core/socket.h
index 03b11c1a69..0b82141659 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -159,6 +159,8 @@ struct Socket {
char *fdname;
RateLimit trigger_limit;
+ usec_t poll_limit_interval;
+ unsigned poll_limit_burst;
};
SocketPeer *socket_peer_ref(SocketPeer *p);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index ad1957d9d7..e2d6bfebf3 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2165,10 +2165,10 @@ static int bus_append_path_property(sd_bus_message *m, const char *field, const
return 1;
}
- if (streq(field, "TriggerLimitBurst"))
+ if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
return bus_append_safe_atou(m, field, eq);
- if (streq(field, "TriggerLimitIntervalSec"))
+ if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
return bus_append_parse_sec_rename(m, field, eq);
return 0;
@@ -2377,7 +2377,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
"MaxConnections",
"MaxConnectionsPerSource",
"KeepAliveProbes",
- "TriggerLimitBurst"))
+ "TriggerLimitBurst",
+ "PollLimitBurst"))
return bus_append_safe_atou(m, field, eq);
if (STR_IN_SET(field, "SocketMode",
@@ -2392,7 +2393,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
"KeepAliveTimeSec",
"KeepAliveIntervalSec",
"DeferAcceptSec",
- "TriggerLimitIntervalSec"))
+ "TriggerLimitIntervalSec",
+ "PollLimitIntervalSec"))
return bus_append_parse_sec_rename(m, field, eq);
if (STR_IN_SET(field, "ReceiveBuffer",