summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-09-23 17:36:21 +0200
committerThomas Haller <thaller@redhat.com>2016-09-26 13:12:02 +0200
commit93396b8d526e99ac26a6e9c9d9b783333fc9b88e (patch)
treee2a3227e5a1e478f64688cc3105f6a0b76a447aa /src
parent1eca446c8c9044c3643c59f73d4396e7ef18d54d (diff)
downloadNetworkManager-93396b8d526e99ac26a6e9c9d9b783333fc9b88e.tar.gz
config: store and load device runtime state to file
The data is still unused, the actual fields might change. Note that the actual state we store is subject to change, according to which data we need. The file format is non stable, as the files don't survive reboot. So there is no backward compatibility to maintain and the format can be changed later.
Diffstat (limited to 'src')
-rw-r--r--src/main.c7
-rw-r--r--src/nm-config.c178
-rw-r--r--src/nm-config.h23
-rw-r--r--src/nm-manager.c64
-rw-r--r--src/nm-manager.h2
5 files changed, 270 insertions, 4 deletions
diff --git a/src/main.c b/src/main.c
index 490dcfe97c..0dca1afad8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -412,6 +412,13 @@ main (int argc, char *argv[])
}
done:
+
+ /* write the device-state to file. Note that we only persist the
+ * state here. We don't bother updating the state as devices
+ * change during regular operation. If NM is killed with SIGKILL,
+ * it misses to update the state. */
+ nm_manager_write_device_state (nm_manager_get ());
+
nm_exported_object_class_set_quitting ();
nm_manager_stop (nm_manager_get ());
diff --git a/src/nm-config.c b/src/nm-config.c
index a4e8eb8cdb..8536a77fd5 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -1870,6 +1870,184 @@ _nm_config_state_set (NMConfig *self,
/*****************************************************************************/
+#define DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE "device"
+#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED "managed"
+#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID "connection-uuid"
+
+static NMConfigDeviceStateData *
+_config_device_state_data_new (int ifindex, GKeyFile *kf)
+{
+ NMConfigDeviceStateData *device_state;
+ NMConfigDeviceStateManagedType managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN;
+ gs_free char *connection_uuid = NULL;
+ gsize len_plus_1;
+
+ nm_assert (ifindex > 0);
+
+ if (kf) {
+ gboolean managed;
+
+ managed = nm_config_keyfile_get_boolean (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
+ FALSE);
+ managed_type = managed
+ ? NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED
+ : NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED;
+
+ if (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);
+ }
+ }
+
+ len_plus_1 = connection_uuid ? strlen (connection_uuid) + 1 : 0;
+
+ device_state = g_malloc (sizeof (NMConfigDeviceStateData) + len_plus_1);
+
+ device_state->ifindex = ifindex;
+ device_state->managed = managed_type;
+ device_state->connection_uuid = NULL;
+ if (connection_uuid) {
+ char *device_state_data;
+
+ device_state_data = (char *) (&device_state[1]);
+ memcpy (device_state_data, connection_uuid, len_plus_1);
+ device_state->connection_uuid = device_state_data;
+ }
+
+ return device_state;
+}
+
+/**
+ * nm_config_device_state_load:
+ * @self: the NMConfig instance
+ * @ifindex: the ifindex for which the state is to load
+ *
+ * Returns: (transfer full): a run state object.
+ * Must be freed with g_free().
+ */
+NMConfigDeviceStateData *
+nm_config_device_state_load (NMConfig *self,
+ int ifindex)
+{
+ NMConfigDeviceStateData *device_state;
+ char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
+ gs_unref_keyfile GKeyFile *kf = NULL;
+ gs_free_error GError *error = NULL;
+
+ g_return_val_if_fail (ifindex > 0, NULL);
+
+ nm_sprintf_buf (path, "%s/%d", NM_CONFIG_DEVICE_STATE_DIR, ifindex);
+
+ kf = nm_config_create_keyfile ();
+ if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, &error))
+ g_clear_pointer (&kf, g_key_file_unref);
+
+ device_state = _config_device_state_data_new (ifindex, kf);
+
+ if (kf) {
+ _LOGT ("device-state: read #%d (%s); managed=%d, connection-uuid=%s%s%s",
+ ifindex, path,
+ device_state->managed,
+ NM_PRINT_FMT_QUOTE_STRING (device_state->connection_uuid));
+ } else {
+ _LOGT ("device-state: read #%d (%s); no persistent state",
+ ifindex, path);
+ }
+
+ return device_state;
+}
+
+gboolean
+nm_config_device_state_write (NMConfig *self,
+ int ifindex,
+ gboolean managed,
+ const char *connection_uuid)
+{
+ char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
+ GError *local = NULL;
+ gs_unref_keyfile GKeyFile *kf = NULL;
+
+ g_return_val_if_fail (NM_IS_CONFIG (self), FALSE);
+ g_return_val_if_fail (ifindex > 0, FALSE);
+ g_return_val_if_fail (!connection_uuid || *connection_uuid, FALSE);
+ g_return_val_if_fail (managed || !connection_uuid, FALSE);
+
+ nm_sprintf_buf (path, "%s/%d", NM_CONFIG_DEVICE_STATE_DIR, ifindex);
+
+ kf = nm_config_create_keyfile ();
+ g_key_file_set_boolean (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
+ !!managed);
+ if (connection_uuid) {
+ g_key_file_set_string (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
+ connection_uuid);
+ }
+
+ 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=%d, connection-uuid=%s%s%s",
+ ifindex, path,
+ (bool) managed,
+ NM_PRINT_FMT_QUOTE_STRING (connection_uuid));
+ return TRUE;
+}
+
+void
+nm_config_device_state_prune_unseen (NMConfig *self,
+ GHashTable *seen_ifindexes)
+{
+ GDir *dir;
+ 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"/")];
+
+ g_return_if_fail (seen_ifindexes);
+
+ dir = g_dir_open (NM_CONFIG_DEVICE_STATE_DIR, 0, NULL);
+ if (!dir)
+ 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)
+ 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);
+ _LOGT ("device-state: prune #%d (%s)", ifindex, buf);
+ (void) unlink (buf);
+ }
+
+ g_dir_close (dir);
+}
+
+/*****************************************************************************/
+
void
nm_config_reload (NMConfig *self, NMConfigChangeFlags reload_flags)
{
diff --git a/src/nm-config.h b/src/nm-config.h
index ef5430ee6c..6ada27672d 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -189,6 +189,29 @@ extern char *_nm_config_match_env;
#define NM_CONFIG_DEVICE_STATE_DIR ""NMRUNDIR"/devices"
+typedef enum {
+ NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN = -1,
+ NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED = 0,
+ NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED = 1,
+} NMConfigDeviceStateManagedType;
+
+typedef struct {
+ int ifindex;
+ NMConfigDeviceStateManagedType managed;
+
+ /* the UUID of the last settings-connection active
+ * on the device. */
+ const char *connection_uuid;
+} NMConfigDeviceStateData;
+
+NMConfigDeviceStateData *nm_config_device_state_load (NMConfig *self,
+ int ifindex);
+gboolean nm_config_device_state_write (NMConfig *self,
+ int ifindex,
+ gboolean managed,
+ const char *connection_uuid);
+void nm_config_device_state_prune_unseen (NMConfig *self, GHashTable *seen_ifindexes);
+
/*****************************************************************************/
#endif /* __NETWORKMANAGER_CONFIG_H__ */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 2335a731bf..efc21c9459 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2083,7 +2083,8 @@ _register_device_factory (NMDeviceFactory *factory, gpointer user_data)
static void
platform_link_added (NMManager *self,
int ifindex,
- const NMPlatformLink *plink)
+ const NMPlatformLink *plink,
+ const NMConfigDeviceStateData *dev_state)
{
NMDeviceFactory *factory;
NMDevice *device = NULL;
@@ -2194,7 +2195,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data)
NMPlatformLink pllink;
pllink = *l; /* make a copy of the link instance */
- platform_link_added (self, data->ifindex, &pllink);
+ platform_link_added (self, data->ifindex, &pllink, NULL);
} else {
NMDevice *device;
GError *error = NULL;
@@ -2249,14 +2250,24 @@ platform_link_cb (NMPlatform *platform,
static void
platform_query_devices (NMManager *self)
{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GArray *links_array;
NMPlatformLink *links;
int i;
links_array = nm_platform_link_get_all (NM_PLATFORM_GET);
links = (NMPlatformLink *) links_array->data;
- for (i = 0; i < links_array->len; i++)
- platform_link_added (self, links[i].ifindex, &links[i]);
+ for (i = 0; i < links_array->len; i++) {
+ gs_free NMConfigDeviceStateData *dev_state = NULL;
+
+ dev_state = nm_config_device_state_load (priv->config,
+ links[i].ifindex);
+
+ platform_link_added (self,
+ links[i].ifindex,
+ &links[i],
+ dev_state);
+ }
g_array_unref (links_array);
}
@@ -4586,6 +4597,51 @@ start_factory (NMDeviceFactory *factory, gpointer user_data)
nm_device_factory_start (factory);
}
+void
+nm_manager_write_device_state (NMManager *self)
+{
+ const GSList *devices;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ gs_unref_hashtable GHashTable *seen_ifindexes = NULL;
+
+ seen_ifindexes = g_hash_table_new (NULL, NULL);
+
+ for (devices = priv->devices; devices; devices = devices->next) {
+ NMDevice *device = NM_DEVICE (devices->data);
+ int ifindex;
+ gboolean managed;
+ NMConnection *settings_connection;
+ const char *uuid = NULL;
+
+ ifindex = nm_device_get_ip_ifindex (device);
+ if (ifindex <= 0)
+ continue;
+ if (ifindex == 1) {
+ /* ignore loopback */
+ continue;
+ }
+
+ if (!nm_platform_link_get (NM_PLATFORM_GET, ifindex))
+ continue;
+
+ managed = nm_device_get_managed (device, FALSE);
+ if (managed) {
+ settings_connection = NM_CONNECTION (nm_device_get_settings_connection (device));
+ if (settings_connection)
+ uuid = nm_connection_get_uuid (settings_connection);
+ }
+
+ if (nm_config_device_state_write (priv->config,
+ ifindex,
+ managed,
+ uuid))
+ g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex));
+ }
+
+ nm_config_device_state_prune_unseen (priv->config,
+ seen_ifindexes);
+}
+
gboolean
nm_manager_start (NMManager *self, GError **error)
{
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 11c4eb4a18..fb97951ce3 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -86,6 +86,8 @@ NMState nm_manager_get_state (NMManager *manager);
const GSList *nm_manager_get_active_connections (NMManager *manager);
GSList * nm_manager_get_activatable_connections (NMManager *manager);
+void nm_manager_write_device_state (NMManager *manager);
+
/* Device handling */
const GSList * nm_manager_get_devices (NMManager *manager);