diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2016-01-15 15:04:39 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2016-01-15 15:17:07 +0100 |
commit | 2a50450c9fd57a94be2b0eda70e6fc97dac4c0df (patch) | |
tree | 9ec6dd623d58c72e81c918cc1894f63496b97cf9 | |
parent | c4bd0cc5cb87801691122c340c7ec0c3f7190ac4 (diff) | |
download | NetworkManager-bg/dns-plugin-ratelimit.tar.gz |
dns-manager: prevent DNS plugins from respawning too quicklybg/dns-plugin-ratelimit
If dnsmasq (or another DNS plugin) exits immediately (for example due
to an already used port), the DNS manager keeps restarting it forever,
wasting system resources and filling logs.
Add a simple rate-limiting mechanism.
-rw-r--r-- | src/dns-manager/nm-dns-manager.c | 50 | ||||
-rw-r--r-- | src/dns-manager/nm-dns-plugin.c | 2 |
2 files changed, 46 insertions, 6 deletions
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 01e8bf1db5..605a5b3874 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -82,6 +82,10 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT) #define NETCONFIG_PATH "/sbin/netconfig" #endif +#define PLUGIN_RATELIMIT_INTERVAL 30 +#define PLUGIN_RATELIMIT_BURST 5 +#define PLUGIN_RATELIMIT_DELAY 300 + NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager); /*********************************************************************************************/ @@ -130,6 +134,12 @@ typedef struct { NMConfig *config; gboolean dns_touched; + + struct { + guint64 ts; + guint num_restarts; + guint timer; + } plugin_ratelimit; } NMDnsManagerPrivate; enum { @@ -799,6 +809,7 @@ update_dns (NMDnsManager *self, g_return_val_if_fail (!error || !*error, FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); + nm_clear_g_source (&priv->plugin_ratelimit.timer); if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) { update = FALSE; @@ -1022,20 +1033,47 @@ plugin_failed (NMDnsPlugin *plugin, gpointer user_data) } } -static void -plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) +static gboolean +plugin_child_quit_update_dns (gpointer user_data) { - NMDnsManager *self = NM_DNS_MANAGER (user_data); GError *error = NULL; - - _LOGW ("plugin %s child quit unexpectedly; refreshing DNS", - nm_dns_plugin_get_name (plugin)); + NMDnsManager *self = NM_DNS_MANAGER (user_data); /* Let the plugin try to spawn the child again */ if (!update_dns (self, FALSE, &error)) { _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } + + return G_SOURCE_REMOVE; +} + +static void +plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) +{ + NMDnsManager *self = NM_DNS_MANAGER (user_data); + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + guint64 ts = nm_utils_get_monotonic_timestamp_ms (); + + _LOGW ("plugin %s child quit unexpectedly", nm_dns_plugin_get_name (plugin)); + + if (!priv->plugin_ratelimit.ts || + (ts - priv->plugin_ratelimit.ts) / 1000 > PLUGIN_RATELIMIT_INTERVAL) { + priv->plugin_ratelimit.ts = ts; + priv->plugin_ratelimit.num_restarts = 0; + } else { + priv->plugin_ratelimit.num_restarts++; + if (priv->plugin_ratelimit.num_restarts > PLUGIN_RATELIMIT_BURST) { + _LOGW ("plugin %s child respawning too fast, delaying update for %u seconds", + nm_dns_plugin_get_name (plugin), PLUGIN_RATELIMIT_DELAY); + priv->plugin_ratelimit.timer = g_timeout_add_seconds (PLUGIN_RATELIMIT_DELAY, + plugin_child_quit_update_dns, + self); + return; + } + } + + plugin_child_quit_update_dns (self); } gboolean diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index a82366962f..9eadf191a9 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -133,6 +133,8 @@ watch_cb (GPid pid, gint status, gpointer user_data) g_free (priv->progname); priv->progname = NULL; + nm_clear_g_source (&priv->watch_id); + g_signal_emit (self, signals[CHILD_QUIT], 0, status); } |