summaryrefslogtreecommitdiff
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 11:30:02 +0200
commit3c4bd9377ae7e617506244a62df09a10d806ac4c (patch)
treefcc469fadd8fd961924e70223eeedf13341cc6ce
parent1eca446c8c9044c3643c59f73d4396e7ef18d54d (diff)
downloadNetworkManager-th/device-state-bgo771890.tar.gz
config: store and load device runtime state to fileth/device-state-bgo771890
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.
-rw-r--r--src/main.c7
-rw-r--r--src/nm-config.c173
-rw-r--r--src/nm-config.h23
-rw-r--r--src/nm-manager.c64
-rw-r--r--src/nm-manager.h2
5 files changed, 265 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..b587f880a2 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -1870,6 +1870,179 @@ _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);
+
+ _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));
+
+ 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: failure to write #%d (%s): %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);