summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dns-manager/nm-dns-manager.c50
-rw-r--r--src/dns-manager/nm-dns-plugin.c2
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);
}