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: 306f9c490b ('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
This commit is contained in:
Jan Vaclav 2026-01-15 11:59:49 +01:00
parent e776f80197
commit 574411b8a5

View file

@ -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);