summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-04-14 13:09:05 +0200
committerThomas Haller <thaller@redhat.com>2022-04-15 09:04:30 +0200
commitcef5b8dd46126f19c208f2469c6b8b6e4aa04030 (patch)
treeb36933ecc18c14da9be734ee9ce2b2275ecf6ded
parentf2abcf20827deaaaf54082dbc74657ab19666dcd (diff)
dns: prevent update-pending to hang indefinitely
For example, if you have a dnsmasq service running and bound to port 53, then NetworkManager's [main].dns=dnsmasq will fail to start. And we keep retrying to start it. But then update pending would hang indefinitely, and devices could not become active. That must not happen. Give the DNS update only 5 seconds. If it's not done by then, assume we have a problem and unblock.
-rw-r--r--src/core/dns/nm-dns-manager.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c
index 0d6ade2b2d..afda300bd2 100644
--- a/src/core/dns/nm-dns-manager.c
+++ b/src/core/dns/nm-dns-manager.c
@@ -56,6 +56,8 @@
#define HAS_NETCONFIG 1
#endif
+#define UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC 5000
+
/*****************************************************************************/
typedef enum { SR_SUCCESS, SR_NOTFOUND, SR_ERROR } SpawnResult;
@@ -92,6 +94,11 @@ typedef struct {
CList ip_data_lst_head;
GVariant *config_variant;
+ /* A DNS plugin should not be marked as pending indefinitely.
+ * We are only blocked if "update_pending" is TRUE and we have
+ * "update_pending_unblock" timer ticking. */
+ GSource *update_pending_unblock;
+
bool ip_data_lst_need_sort : 1;
bool configs_lst_need_sort : 1;
@@ -222,6 +229,25 @@ _update_pending_detect(NMDnsManager *self)
return FALSE;
}
+static gboolean
+_update_pending_unblock_cb(gpointer user_data)
+{
+ NMDnsManager *self = user_data;
+ NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
+
+ nm_assert(priv->update_pending);
+ nm_assert(priv->update_pending_unblock);
+ nm_assert(_update_pending_detect(self));
+
+ nm_clear_g_source_inst(&priv->update_pending_unblock);
+
+ _LOGW(
+ "update-pending changed: DNS plugin did not become ready again. Assume something is wrong");
+
+ _notify(self, PROP_UPDATE_PENDING);
+ return G_SOURCE_CONTINUE;
+}
+
static void
_update_pending_maybe_changed(NMDnsManager *self)
{
@@ -232,6 +258,14 @@ _update_pending_maybe_changed(NMDnsManager *self)
if (priv->update_pending == update_pending)
return;
+ if (update_pending) {
+ nm_assert(!priv->update_pending_unblock);
+ priv->update_pending_unblock = nm_g_timeout_add_source(UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC,
+ _update_pending_unblock_cb,
+ self);
+ } else
+ nm_clear_g_source_inst(&priv->update_pending_unblock);
+
priv->update_pending = update_pending;
_LOGD("update-pending changed: %spending", update_pending ? "" : "not ");
_notify(self, PROP_UPDATE_PENDING);
@@ -252,7 +286,12 @@ nm_dns_manager_get_update_pending(NMDnsManager *self)
priv = NM_DNS_MANAGER_GET_PRIVATE(self);
nm_assert(priv->update_pending == _update_pending_detect(self));
- return priv->update_pending;
+ nm_assert(priv->update_pending || !priv->update_pending_unblock);
+
+ /* update-pending can only be TRUE for a certain time (before we assume
+ * something is really wrong with the plugin). That is, as long as
+ * update_pending_unblock is ticking. */
+ return !!priv->update_pending_unblock;
}
/*****************************************************************************/
@@ -2727,6 +2766,8 @@ dispose(GObject *object)
_clear_sd_resolved_plugin(self);
_clear_plugin(self);
+ nm_clear_g_source_inst(&priv->update_pending_unblock);
+
c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_data_lst_head, ip_data_lst)
_dns_config_ip_data_free(ip_data);