mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-05 15:00:25 +01:00
core: cache device state in NMConfig and load all at once
NMManager will need to know the state of all device at once. Hence, load it once and cache it in NMConfig. Note that this wastes a bit of memory in the order of O(number-of-interfaces). But each device state entry is rather small, and we always consume memory in the order of O(number-of-interfaces).
This commit is contained in:
parent
3f38b76515
commit
ea08df925f
4 changed files with 158 additions and 73 deletions
|
|
@ -13639,6 +13639,7 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze)
|
|||
gboolean success_read;
|
||||
int ifindex;
|
||||
const NMPlatformLink *pllink;
|
||||
const NMConfigDeviceStateData *dev_state;
|
||||
|
||||
if (priv->hw_addr_perm) {
|
||||
/* the permanent hardware address is only read once and not
|
||||
|
|
@ -13698,23 +13699,19 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze)
|
|||
/* We also persist our choice of the fake address to the device state
|
||||
* file to use the same address on restart of NetworkManager.
|
||||
* First, try to reload the address from the state file. */
|
||||
{
|
||||
gs_free NMConfigDeviceStateData *dev_state = NULL;
|
||||
|
||||
dev_state = nm_config_device_state_load (ifindex);
|
||||
if ( dev_state
|
||||
&& dev_state->perm_hw_addr_fake
|
||||
&& nm_utils_hwaddr_aton (dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len)
|
||||
&& !nm_utils_hwaddr_matches (buf, priv->hw_addr_len, priv->hw_addr, -1)) {
|
||||
_LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use from statefile: %s, current: %s)",
|
||||
success_read
|
||||
? "read HW addr length of permanent MAC address differs"
|
||||
: "unable to read permanent MAC address",
|
||||
dev_state->perm_hw_addr_fake,
|
||||
priv->hw_addr);
|
||||
priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
|
||||
goto notify_and_out;
|
||||
}
|
||||
dev_state = nm_config_device_state_get (nm_config_get (), ifindex);
|
||||
if ( dev_state
|
||||
&& dev_state->perm_hw_addr_fake
|
||||
&& nm_utils_hwaddr_aton (dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len)
|
||||
&& !nm_utils_hwaddr_matches (buf, priv->hw_addr_len, priv->hw_addr, -1)) {
|
||||
_LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use from statefile: %s, current: %s)",
|
||||
success_read
|
||||
? "read HW addr length of permanent MAC address differs"
|
||||
: "unable to read permanent MAC address",
|
||||
dev_state->perm_hw_addr_fake,
|
||||
priv->hw_addr);
|
||||
priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
|
||||
goto notify_and_out;
|
||||
}
|
||||
|
||||
_LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use current: %s)",
|
||||
|
|
|
|||
190
src/nm-config.c
190
src/nm-config.c
|
|
@ -121,6 +121,14 @@ typedef struct {
|
|||
* because the state changes only on explicit actions from the daemon
|
||||
* itself. */
|
||||
State *state;
|
||||
|
||||
/* the hash table of device states. It is only loaded from disk
|
||||
* once and kept immutable afterwards.
|
||||
*
|
||||
* We also read all state file at once. We don't want to support
|
||||
* that they are changed outside of NM (at least not while NM is running).
|
||||
* Hence, we read them once, that's it. */
|
||||
GHashTable *device_states;
|
||||
} NMConfigPrivate;
|
||||
|
||||
struct _NMConfig {
|
||||
|
|
@ -1945,46 +1953,45 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf)
|
|||
gint nm_owned = -1;
|
||||
char *p;
|
||||
|
||||
nm_assert (kf);
|
||||
nm_assert (ifindex > 0);
|
||||
|
||||
if (kf) {
|
||||
switch (nm_config_keyfile_get_boolean (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
|
||||
-1)) {
|
||||
case TRUE:
|
||||
managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED;
|
||||
connection_uuid = nm_config_keyfile_get_value (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
|
||||
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
||||
break;
|
||||
case FALSE:
|
||||
managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED;
|
||||
break;
|
||||
case -1:
|
||||
/* missing property in keyfile. */
|
||||
break;
|
||||
}
|
||||
|
||||
perm_hw_addr_fake = nm_config_keyfile_get_value (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_PERM_HW_ADDR_FAKE,
|
||||
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
||||
if (perm_hw_addr_fake) {
|
||||
char *normalized;
|
||||
|
||||
normalized = nm_utils_hwaddr_canonical (perm_hw_addr_fake, -1);
|
||||
g_free (perm_hw_addr_fake);
|
||||
perm_hw_addr_fake = normalized;
|
||||
}
|
||||
|
||||
nm_owned = nm_config_keyfile_get_boolean (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED,
|
||||
-1);
|
||||
switch (nm_config_keyfile_get_boolean (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
|
||||
-1)) {
|
||||
case TRUE:
|
||||
managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED;
|
||||
connection_uuid = nm_config_keyfile_get_value (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
|
||||
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
||||
break;
|
||||
case FALSE:
|
||||
managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED;
|
||||
break;
|
||||
case -1:
|
||||
/* missing property in keyfile. */
|
||||
break;
|
||||
}
|
||||
|
||||
perm_hw_addr_fake = nm_config_keyfile_get_value (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_PERM_HW_ADDR_FAKE,
|
||||
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
||||
if (perm_hw_addr_fake) {
|
||||
char *normalized;
|
||||
|
||||
normalized = nm_utils_hwaddr_canonical (perm_hw_addr_fake, -1);
|
||||
g_free (perm_hw_addr_fake);
|
||||
perm_hw_addr_fake = normalized;
|
||||
}
|
||||
|
||||
nm_owned = nm_config_keyfile_get_boolean (kf,
|
||||
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||||
DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED,
|
||||
-1);
|
||||
|
||||
connection_uuid_len = connection_uuid ? strlen (connection_uuid) + 1 : 0;
|
||||
perm_hw_addr_fake_len = perm_hw_addr_fake ? strlen (perm_hw_addr_fake) + 1 : 0;
|
||||
|
||||
|
|
@ -2034,14 +2041,13 @@ nm_config_device_state_load (int ifindex)
|
|||
|
||||
kf = nm_config_create_keyfile ();
|
||||
if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, NULL))
|
||||
g_clear_pointer (&kf, g_key_file_unref);
|
||||
return NULL;
|
||||
|
||||
device_state = _config_device_state_data_new (ifindex, kf);
|
||||
nm_owned_str = device_state->nm_owned == TRUE ?
|
||||
", nm-owned=1" :
|
||||
(device_state->nm_owned == FALSE ? ", nm-owned=0" : "");
|
||||
|
||||
|
||||
_LOGT ("device-state: %s #%d (%s); managed=%s%s%s%s%s%s%s%s",
|
||||
kf ? "read" : "miss",
|
||||
ifindex, path,
|
||||
|
|
@ -2053,6 +2059,49 @@ nm_config_device_state_load (int ifindex)
|
|||
return device_state;
|
||||
}
|
||||
|
||||
static int
|
||||
_device_state_parse_filename (const char *filename)
|
||||
{
|
||||
if (!filename || !filename[0])
|
||||
return 0;
|
||||
if (!NM_STRCHAR_ALL (filename, ch, g_ascii_isdigit (ch)))
|
||||
return 0;
|
||||
return _nm_utils_ascii_str_to_int64 (filename, 10, 1, G_MAXINT, 0);
|
||||
}
|
||||
|
||||
GHashTable *
|
||||
nm_config_device_state_load_all (void)
|
||||
{
|
||||
GHashTable *states;
|
||||
GDir *dir;
|
||||
const char *fn;
|
||||
int ifindex;
|
||||
|
||||
states = g_hash_table_new_full (nm_direct_hash, NULL, NULL, g_free);
|
||||
|
||||
dir = g_dir_open (NM_CONFIG_DEVICE_STATE_DIR, 0, NULL);
|
||||
if (!dir)
|
||||
return states;
|
||||
|
||||
while ((fn = g_dir_read_name (dir))) {
|
||||
NMConfigDeviceStateData *state;
|
||||
|
||||
ifindex = _device_state_parse_filename (fn);
|
||||
if (ifindex <= 0)
|
||||
continue;
|
||||
|
||||
state = nm_config_device_state_load (ifindex);
|
||||
if (!state)
|
||||
continue;
|
||||
|
||||
if (!nm_g_hash_table_insert (states, GINT_TO_POINTER (ifindex), state))
|
||||
nm_assert_not_reached ();
|
||||
}
|
||||
g_dir_close (dir);
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_config_device_state_write (int ifindex,
|
||||
NMConfigDeviceStateManagedType managed,
|
||||
|
|
@ -2121,7 +2170,6 @@ nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes)
|
|||
const char *fn;
|
||||
int ifindex;
|
||||
gsize fn_len;
|
||||
gsize i;
|
||||
char buf[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR"/") + 30 + 3] = NM_CONFIG_DEVICE_STATE_DIR"/";
|
||||
char *buf_p = &buf[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR"/")];
|
||||
|
||||
|
|
@ -2132,24 +2180,20 @@ nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes)
|
|||
return;
|
||||
|
||||
while ((fn = g_dir_read_name (dir))) {
|
||||
fn_len = strlen (fn);
|
||||
|
||||
/* skip over file names that are not plain integers. */
|
||||
for (i = 0; i < fn_len; i++) {
|
||||
if (!g_ascii_isdigit (fn[i]))
|
||||
break;
|
||||
}
|
||||
if (fn_len == 0 || i != fn_len)
|
||||
ifindex = _device_state_parse_filename (fn);
|
||||
if (ifindex <= 0)
|
||||
continue;
|
||||
|
||||
ifindex = _nm_utils_ascii_str_to_int64 (fn, 10, 1, G_MAXINT, 0);
|
||||
if (!ifindex)
|
||||
continue;
|
||||
|
||||
if (g_hash_table_contains (seen_ifindexes, GINT_TO_POINTER (ifindex)))
|
||||
continue;
|
||||
|
||||
memcpy (buf_p, fn, fn_len + 1);
|
||||
fn_len = strlen (fn) + 1;
|
||||
nm_assert (&buf_p[fn_len] < &buf[G_N_ELEMENTS (buf)]);
|
||||
memcpy (buf_p, fn, fn_len);
|
||||
nm_assert (({
|
||||
char bb[30];
|
||||
nm_sprintf_buf (bb, "%d", ifindex);
|
||||
nm_streq0 (bb, buf_p);
|
||||
}));
|
||||
_LOGT ("device-state: prune #%d (%s)", ifindex, buf);
|
||||
(void) unlink (buf);
|
||||
}
|
||||
|
|
@ -2159,6 +2203,46 @@ nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static GHashTable *
|
||||
_device_state_get_all (NMConfig *self)
|
||||
{
|
||||
NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
|
||||
|
||||
if (G_UNLIKELY (!priv->device_states))
|
||||
priv->device_states = nm_config_device_state_load_all ();
|
||||
return priv->device_states;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_config_device_state_get_all:
|
||||
* @self: the #NMConfig
|
||||
*
|
||||
* This function exists to give convenient access to all
|
||||
* device states. Do not ever try to modify the returned
|
||||
* hash, it's supposed to be immutable.
|
||||
*
|
||||
* Returns: the internal #GHashTable object with all device states.
|
||||
*/
|
||||
const GHashTable *
|
||||
nm_config_device_state_get_all (NMConfig *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CONFIG (self), NULL);
|
||||
|
||||
return _device_state_get_all (self);
|
||||
}
|
||||
|
||||
const NMConfigDeviceStateData *
|
||||
nm_config_device_state_get (NMConfig *self,
|
||||
int ifindex)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CONFIG (self), NULL);
|
||||
g_return_val_if_fail (ifindex > 0 , NULL);
|
||||
|
||||
return g_hash_table_lookup (_device_state_get_all (self), GINT_TO_POINTER (ifindex));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
nm_config_reload (NMConfig *self, NMConfigChangeFlags reload_flags)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ struct _NMConfigDeviceStateData {
|
|||
};
|
||||
|
||||
NMConfigDeviceStateData *nm_config_device_state_load (int ifindex);
|
||||
GHashTable *nm_config_device_state_load_all (void);
|
||||
gboolean nm_config_device_state_write (int ifindex,
|
||||
NMConfigDeviceStateManagedType managed,
|
||||
const char *perm_hw_addr_fake,
|
||||
|
|
@ -232,6 +233,10 @@ gboolean nm_config_device_state_write (int ifindex,
|
|||
gint nm_owned);
|
||||
void nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes);
|
||||
|
||||
const GHashTable *nm_config_device_state_get_all (NMConfig *self);
|
||||
const NMConfigDeviceStateData *nm_config_device_state_get (NMConfig *self,
|
||||
int ifindex);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* __NETWORKMANAGER_CONFIG_H__ */
|
||||
|
|
|
|||
|
|
@ -2641,10 +2641,9 @@ platform_query_devices (NMManager *self)
|
|||
return;
|
||||
for (i = 0; i < links->len; i++) {
|
||||
const NMPlatformLink *link = NMP_OBJECT_CAST_LINK (links->pdata[i]);
|
||||
gs_free NMConfigDeviceStateData *dev_state = NULL;
|
||||
|
||||
dev_state = nm_config_device_state_load (link->ifindex);
|
||||
const NMConfigDeviceStateData *dev_state;
|
||||
|
||||
dev_state = nm_config_device_state_get (priv->config, link->ifindex);
|
||||
platform_link_added (self,
|
||||
link->ifindex,
|
||||
link,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue