diff options
-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); } |