From d5256111ba742fb38b32b22b143cc4eeddba3869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= Date: Tue, 24 Feb 2026 11:30:15 +0100 Subject: [PATCH] core: config: allow to store 'managed' configs to NM-intern To support setting devices as managed or unmanaged via D-Bus API in a permanent way, we need a way to store this configuration on disk. Before this commit, only config files manually edited allowed it. Following commits will make use of the new functions to store [device-*] sections into NetworkManager-intern.conf depending on D-Bus method invocations. --- src/core/nm-config.c | 124 ++++++++++++++++++++++++++++++++ src/core/nm-config.h | 7 ++ src/libnm-base/nm-config-base.h | 3 + 3 files changed, 134 insertions(+) diff --git a/src/core/nm-config.c b/src/core/nm-config.c index 472d783053..8668c54a5c 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -2076,6 +2076,130 @@ nm_config_set_connectivity_check_enabled(NMConfig *self, gboolean enabled) g_key_file_unref(keyfile); } +/*****************************************************************************/ + +/** + * nm_config_get_device_managed: + * @self: the NMConfig instance + * @ifname: the interface name + * + * Returns: the current managed state of the device in the intern keyfile. If it + * is not set or it's invalid, returns %NM_TERNARY_DEFAULT. + */ +NMTernary +nm_config_get_device_managed(NMConfig *self, const char *ifname) +{ + NMConfigPrivate *priv; + const GKeyFile *keyfile = NULL; + gs_free char *group = NULL; + + g_return_val_if_fail(NM_IS_CONFIG(self), FALSE); + g_return_val_if_fail(NM_CONFIG_GET_PRIVATE(self)->config_data, FALSE); + g_return_val_if_fail(ifname, FALSE); + + priv = NM_CONFIG_GET_PRIVATE(self); + keyfile = _nm_config_data_get_keyfile_intern(priv->config_data); + group = g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-%s", ifname); + + if (!keyfile) + return NM_TERNARY_DEFAULT; + + return (NMTernary) nm_config_keyfile_get_boolean(keyfile, + group, + NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, + NM_TERNARY_DEFAULT); +} + +/** + * nm_config_set_device_managed: + * @self: the NMConfig instance + * @device: the NMDevice instance associated with this config change + * @managed: the managed state to set + * @by_mac: if %TRUE, match by MAC address, otherwise by interface name. This is + * only used when @managed = TRUE. + * @error: return location for a #GError, or %NULL + * + * Sets the managed state of the device to the intern keyfile. Here we store the + * configuration received via the D-Bus API. Configurations from other config + * files are still in place and may have higher precedence. + * + * Prior to setting the new state, the existing configuration is removed. If + * @managed is set to %NM_TERNARY_DEFAULT, we only do the removal of the previous + * configuration. + */ +gboolean +nm_config_set_device_managed(NMConfig *self, + NMDevice *device, + NMTernary managed, + gboolean by_mac, + GError **error) +{ + NMConfigPrivate *priv; + g_autoptr(GKeyFile) keyfile = NULL; + char *group; + gs_free char *group_by_name = NULL; + gs_free char *group_by_mac = NULL; + gs_free char *match_value = NULL; + gboolean changed = FALSE; + const char *ifname = nm_device_get_iface(device); + const char *hwaddr = nm_device_get_permanent_hw_address(device); + guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX]; + char hwaddr_chars[NM_UTILS_HWADDR_LEN_MAX * 3 + 1]; + gsize hwaddr_bin_len; + + g_return_val_if_fail(NM_IS_CONFIG(self), FALSE); + g_return_val_if_fail(NM_CONFIG_GET_PRIVATE(self)->config_data, FALSE); + g_return_val_if_fail(ifname && hwaddr, FALSE); + + /* Get a string from the hwaddr that we can use as keyfile's group name.*/ + if (!_nm_utils_hwaddr_aton(hwaddr, hwaddr_bin, sizeof(hwaddr_bin), &hwaddr_bin_len)) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_ARGUMENT, + "Invalid MAC address: %s", + hwaddr); + return FALSE; + } + nm_utils_bin2hexstr_full(hwaddr_bin, hwaddr_bin_len, '-', TRUE, hwaddr_chars); + + priv = NM_CONFIG_GET_PRIVATE(self); + keyfile = nm_config_data_clone_keyfile_intern(priv->config_data); + group_by_name = g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-%s", ifname); + group_by_mac = g_strdup_printf(NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE "-%s", hwaddr_chars); + + /* Remove existing configs. Search them by group name [.intern.device-*]. In + * the intern file, 'device' sections are only used for this purpose, so we won't remove + * any other device's config. */ + if (g_key_file_remove_group(keyfile, group_by_name, NULL) + || g_key_file_remove_group(keyfile, group_by_mac, NULL)) + changed = TRUE; + + /* If the new state is not explicitly TRUE of FALSE, we only remove the configs */ + if (managed == NM_TERNARY_DEFAULT) + goto done; + + /* Set new values */ + if (by_mac) { + group = group_by_mac; + match_value = g_strdup_printf("mac:%s", hwaddr); + } else { + group = group_by_name; + match_value = g_strdup_printf("interface-name:=%s", ifname); + } + + g_key_file_set_value(keyfile, group, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE, match_value); + g_key_file_set_value(keyfile, group, NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, managed ? "1" : "0"); + changed = TRUE; + +done: + if (changed) + nm_config_set_values(self, keyfile, TRUE, FALSE); + + return TRUE; +} + +/*****************************************************************************/ + /** * nm_config_set_values: * @self: the NMConfig instance diff --git a/src/core/nm-config.h b/src/core/nm-config.h index 5518184ce3..2a3b9f4759 100644 --- a/src/core/nm-config.h +++ b/src/core/nm-config.h @@ -142,6 +142,13 @@ gboolean nm_config_set_global_dns(NMConfig *self, NMGlobalDnsConfig *global_dns, void nm_config_set_connectivity_check_enabled(NMConfig *self, gboolean enabled); +NMTernary nm_config_get_device_managed(NMConfig *self, const char *ifname); +gboolean nm_config_set_device_managed(NMConfig *self, + NMDevice *device, + NMTernary managed, + gboolean by_mac, + GError **error); + /* internal defines ... */ extern guint _nm_config_match_nm_version; extern char *_nm_config_match_env; diff --git a/src/libnm-base/nm-config-base.h b/src/libnm-base/nm-config-base.h index e8d46ddc09..07e3fe3ccc 100644 --- a/src/libnm-base/nm-config-base.h +++ b/src/libnm-base/nm-config-base.h @@ -90,4 +90,7 @@ #define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN \ NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN +#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_DEVICE \ + NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE + #endif /* __NM_CONFIG_BASE_H__ */