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.
This commit is contained in:
Íñigo Huguet 2026-02-24 11:30:15 +01:00
parent 02d7d66808
commit d5256111ba
3 changed files with 134 additions and 0 deletions

View file

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

View file

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

View file

@ -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__ */