diff options
Diffstat (limited to 'src/nm-config.c')
| -rw-r--r-- | src/nm-config.c | 266 |
1 files changed, 208 insertions, 58 deletions
diff --git a/src/nm-config.c b/src/nm-config.c index de727c98..29f0d517 100644 --- a/src/nm-config.c +++ b/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 { @@ -182,6 +190,33 @@ nm_config_keyfile_get_boolean (const GKeyFile *keyfile, return nm_config_parse_boolean (str, default_value); } +gint64 +nm_config_keyfile_get_int64 (const GKeyFile *keyfile, + const char *section, + const char *key, + guint base, + gint64 min, + gint64 max, + gint64 fallback) +{ + gint64 v; + int errsv; + char *str; + + g_return_val_if_fail (keyfile, fallback); + g_return_val_if_fail (section, fallback); + g_return_val_if_fail (key, fallback); + + str = g_key_file_get_value ((GKeyFile *) keyfile, section, key, NULL); + v = _nm_utils_ascii_str_to_int64 (str, base, min, max, fallback); + if (str) { + errsv = errno; + g_free (str); + errno = errsv; + } + return v; +} + char * nm_config_keyfile_get_value (const GKeyFile *keyfile, const char *section, @@ -1898,6 +1933,8 @@ _nm_config_state_set (NMConfig *self, #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_PERM_HW_ADDR_FAKE "perm-hw-addr-fake" #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID "connection-uuid" #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED "nm-owned" +#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_ASPIRED "route-metric-default-aspired" +#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_EFFECTIVE "route-metric-default-effective" NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), @@ -1917,47 +1954,63 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf) gsize perm_hw_addr_fake_len; gint nm_owned = -1; char *p; + guint32 route_metric_default_effective; + guint32 route_metric_default_aspired; + 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); + + /* metric zero is not a valid metric. While zero valid for IPv4, for IPv6 it is an alias + * for 1024. Since we handle here IPv4 and IPv6 the same, we cannot allow zero. */ + route_metric_default_effective = nm_config_keyfile_get_int64 (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_EFFECTIVE, + 10, 1, G_MAXUINT32, 0); + if (route_metric_default_effective) { + route_metric_default_aspired = nm_config_keyfile_get_int64 (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_EFFECTIVE, + 10, 1, route_metric_default_effective, + route_metric_default_effective); + } else + route_metric_default_aspired = 0; + 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; @@ -1970,6 +2023,8 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf) device_state->connection_uuid = NULL; device_state->perm_hw_addr_fake = NULL; device_state->nm_owned = nm_owned; + device_state->route_metric_default_aspired = route_metric_default_aspired; + device_state->route_metric_default_effective = route_metric_default_effective; p = (char *) (&device_state[1]); if (connection_uuid) { @@ -2007,31 +2062,77 @@ 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", + _LOGT ("device-state: %s #%d (%s); managed=%s%s%s%s%s%s%s%s, route-metric-default=%"G_GUINT32_FORMAT"-%"G_GUINT32_FORMAT"", kf ? "read" : "miss", ifindex, path, _device_state_managed_type_to_str (device_state->managed), NM_PRINT_FMT_QUOTED (device_state->connection_uuid, ", connection-uuid=", device_state->connection_uuid, "", ""), NM_PRINT_FMT_QUOTED (device_state->perm_hw_addr_fake, ", perm-hw-addr-fake=", device_state->perm_hw_addr_fake, "", ""), - nm_owned_str); + nm_owned_str, + device_state->route_metric_default_aspired, + device_state->route_metric_default_effective); 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, const char *perm_hw_addr_fake, const char *connection_uuid, - gint nm_owned) + gint nm_owned, + guint32 route_metric_default_aspired, + guint32 route_metric_default_effective) { char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60]; GError *local = NULL; @@ -2073,17 +2174,31 @@ nm_config_device_state_write (int ifindex, nm_owned); } + if (route_metric_default_effective != 0) { + g_key_file_set_int64 (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_EFFECTIVE, + route_metric_default_effective); + if (route_metric_default_aspired != route_metric_default_effective) { + g_key_file_set_int64 (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_ASPIRED, + route_metric_default_aspired); + } + } if (!g_key_file_save_to_file (kf, path, &local)) { _LOGW ("device-state: write #%d (%s) failed: %s", ifindex, path, local->message); g_error_free (local); return FALSE; } - _LOGT ("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s", + _LOGT ("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s, route-metric-default=%"G_GUINT32_FORMAT"-%"G_GUINT32_FORMAT"", ifindex, path, _device_state_managed_type_to_str (managed), NM_PRINT_FMT_QUOTED (connection_uuid, ", connection-uuid=", connection_uuid, "", ""), - NM_PRINT_FMT_QUOTED (perm_hw_addr_fake, ", perm-hw-addr-fake=", perm_hw_addr_fake, "", "")); + NM_PRINT_FMT_QUOTED (perm_hw_addr_fake, ", perm-hw-addr-fake=", perm_hw_addr_fake, "", ""), + route_metric_default_aspired, + route_metric_default_effective); return TRUE; } @@ -2094,7 +2209,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"/")]; @@ -2105,24 +2219,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); } @@ -2132,6 +2242,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) { |