From 574411b8a56ebea82f5dcc62c0b31bc95747fb10 Mon Sep 17 00:00:00 2001 From: Jan Vaclav Date: Thu, 15 Jan 2026 11:59:49 +0100 Subject: [PATCH] vpn: wait for device to become available before creating l3cd In some situations, we will have a defined interface index, but no device, because the idle source was not processed yet. Reschedule _check_complete() in an idle source, so that it runs after the device is processed. Fixes: 306f9c490b2a ('vpn: Use nm_device_create_l3_config_data_from_connection if possible') Resolves: https://issues.redhat.com/browse/RHEL-125796 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2347 --- src/core/vpn/nm-vpn-connection.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index 0b36459cf7..54478c5362 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -175,6 +175,7 @@ typedef struct { }; GSource *init_fail_on_idle_source; + GSource *check_device_added_idle_source; GSource *connect_timeout_source; GCancellable *main_cancellable; GVariant *connect_hash; @@ -229,6 +230,8 @@ static void _set_vpn_state(NMVpnConnection *self, static void _l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMVpnConnection *self); +static void _check_complete(NMVpnConnection *self, gboolean success); + /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_VPN @@ -1405,6 +1408,18 @@ fw_change_zone_cb(NMFirewalldManager *firewalld_manager, _apply_config(self); } +static gboolean +_check_device_added_idle_cb(gpointer user_data) +{ + NMVpnConnection *self = user_data; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + _check_complete(self, TRUE); + nm_clear_g_source_inst(&priv->check_device_added_idle_source); + + return G_SOURCE_CONTINUE; +} + static void _check_complete(NMVpnConnection *self, gboolean success) { @@ -1442,13 +1457,24 @@ _check_complete(NMVpnConnection *self, gboolean success) connection = _get_applied_connection(self); ifindex = nm_vpn_connection_get_ip_ifindex(self, FALSE); + device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, ifindex); + + /* We have a defined interface index, but the device is not processed yet. + * The processing of the new kernel link could be queued in an idle handler, + * so schedule an idle handler once to check if the device has been processed. + */ + if (ifindex > 0 && !device && !priv->check_device_added_idle_source) { + priv->check_device_added_idle_source = + nm_g_idle_add_source(_check_device_added_idle_cb, self); + return; + } + /* Use nm_device_create_l3_config_data_from_connection here if possible. This ensures that * connection properties like mdns, llmnr, dns-over-tls or dnssec are applied to vpn connections * If this vpn connection does not have its own device resort to nm_l3_config_data_new_from_connection * since we can't properly apply these properties anyway */ if (ifindex > 0) { - device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, ifindex); nm_assert(device); l3cd = nm_device_create_l3_config_data_from_connection(device, connection); } else { @@ -3042,6 +3068,8 @@ dispose(GObject *object) nm_clear_g_source_inst(&priv->init_fail_on_idle_source); + nm_clear_g_source_inst(&priv->check_device_added_idle_source); + nm_clear_g_cancellable(&priv->main_cancellable); nm_clear_g_source_inst(&priv->start_timeout_source);