You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1516 lines
58 KiB
1516 lines
58 KiB
7 years ago
|
From e7d51475a855f29f124b12e1de8709c2addb8be2 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Wed, 6 Dec 2017 13:16:30 +0100
|
||
|
Subject: [PATCH 1/7] device: expose nm_device_get_route_metric_default()
|
||
|
|
||
|
(cherry picked from commit 989b5fabaac95f9367fb5f1c730db5dca7eab0de)
|
||
|
(cherry picked from commit ea78f156f2ef3402a5c4dde9c395cbf720b7aa4c)
|
||
|
---
|
||
|
src/devices/nm-device.c | 8 ++++----
|
||
|
src/devices/nm-device.h | 2 ++
|
||
|
2 files changed, 6 insertions(+), 4 deletions(-)
|
||
|
|
||
|
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
|
||
|
index f75cc86e3..8179dbd3b 100644
|
||
|
--- a/src/devices/nm-device.c
|
||
|
+++ b/src/devices/nm-device.c
|
||
|
@@ -1616,8 +1616,8 @@ nm_device_get_metered (NMDevice *self)
|
||
|
return NM_DEVICE_GET_PRIVATE (self)->metered;
|
||
|
}
|
||
|
|
||
|
-static guint32
|
||
|
-_get_route_metric_default (NMDevice *self)
|
||
|
+guint32
|
||
|
+nm_device_get_route_metric_default (NMDeviceType device_type)
|
||
|
{
|
||
|
/* Device 'priority' is used for the default route-metric and is based on
|
||
|
* the device type. The settings ipv4.route-metric and ipv6.route-metric
|
||
|
@@ -1636,7 +1636,7 @@ _get_route_metric_default (NMDevice *self)
|
||
|
* metrics (except for IPv6, where 0 means 1024).
|
||
|
*/
|
||
|
|
||
|
- switch (nm_device_get_device_type (self)) {
|
||
|
+ switch (device_type) {
|
||
|
/* 50 is reserved for VPN (NM_VPN_ROUTE_METRIC_DEFAULT) */
|
||
|
case NM_DEVICE_TYPE_ETHERNET:
|
||
|
case NM_DEVICE_TYPE_VETH:
|
||
|
@@ -1765,7 +1765,7 @@ nm_device_get_route_metric (NMDevice *self,
|
||
|
if (route_metric >= 0)
|
||
|
goto out;
|
||
|
}
|
||
|
- route_metric = _get_route_metric_default (self);
|
||
|
+ route_metric = nm_device_get_route_metric_default (nm_device_get_device_type (self));
|
||
|
out:
|
||
|
return nm_utils_ip_route_metric_normalize (addr_family, route_metric);
|
||
|
}
|
||
|
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
|
||
|
index 810a613dd..ac73ee0c4 100644
|
||
|
--- a/src/devices/nm-device.h
|
||
|
+++ b/src/devices/nm-device.h
|
||
|
@@ -450,6 +450,8 @@ NMMetered nm_device_get_metered (NMDevice *dev);
|
||
|
guint32 nm_device_get_route_table (NMDevice *self, int addr_family, gboolean fallback_main);
|
||
|
guint32 nm_device_get_route_metric (NMDevice *dev, int addr_family);
|
||
|
|
||
|
+guint32 nm_device_get_route_metric_default (NMDeviceType device_type);
|
||
|
+
|
||
|
const char * nm_device_get_hw_address (NMDevice *dev);
|
||
|
const char * nm_device_get_permanent_hw_address (NMDevice *self);
|
||
|
const char * nm_device_get_permanent_hw_address_full (NMDevice *self,
|
||
|
--
|
||
|
2.14.3
|
||
|
|
||
|
|
||
|
From 009ce5a739ec760acc38e8265776570e5d1a6a34 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Wed, 6 Dec 2017 12:49:21 +0100
|
||
|
Subject: [PATCH 2/7] core: add nm_config_keyfile_get_int64() util
|
||
|
|
||
|
(cherry picked from commit 3f38b765158c2ffcec7d1b314c3ba6aea3bc3e7b)
|
||
|
(cherry picked from commit 42fbc9410ba5c131e84c21d073d3d818feb2666d)
|
||
|
---
|
||
|
src/nm-config.c | 27 +++++++++++++++++++++++++++
|
||
|
src/nm-config.h | 7 +++++++
|
||
|
2 files changed, 34 insertions(+)
|
||
|
|
||
|
diff --git a/src/nm-config.c b/src/nm-config.c
|
||
|
index de727c988..c344d5cd1 100644
|
||
|
--- a/src/nm-config.c
|
||
|
+++ b/src/nm-config.c
|
||
|
@@ -182,6 +182,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,
|
||
|
diff --git a/src/nm-config.h b/src/nm-config.h
|
||
|
index 8bdd5002d..5b2dc65c4 100644
|
||
|
--- a/src/nm-config.h
|
||
|
+++ b/src/nm-config.h
|
||
|
@@ -165,6 +165,13 @@ gint nm_config_keyfile_get_boolean (const GKeyFile *keyfile,
|
||
|
const char *section,
|
||
|
const char *key,
|
||
|
gint 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);
|
||
|
char *nm_config_keyfile_get_value (const GKeyFile *keyfile,
|
||
|
const char *section,
|
||
|
const char *key,
|
||
|
--
|
||
|
2.14.3
|
||
|
|
||
|
|
||
|
From 412200a581b00c76757afb2250c3a9e3e719ca6b Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Wed, 6 Dec 2017 13:09:31 +0100
|
||
|
Subject: [PATCH 3/7] 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).
|
||
|
|
||
|
(cherry picked from commit ea08df925f6a01e30ddcea4c15cea98d532593c6)
|
||
|
(cherry picked from commit 7b899334068c6945b0604b37510d91b02cbe62d9)
|
||
|
---
|
||
|
src/devices/nm-device.c | 31 ++++----
|
||
|
src/nm-config.c | 186 +++++++++++++++++++++++++++++++++++-------------
|
||
|
src/nm-config.h | 5 ++
|
||
|
src/nm-manager.c | 5 +-
|
||
|
4 files changed, 156 insertions(+), 71 deletions(-)
|
||
|
|
||
|
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
|
||
|
index 8179dbd3b..755589674 100644
|
||
|
--- a/src/devices/nm-device.c
|
||
|
+++ b/src/devices/nm-device.c
|
||
|
@@ -13512,6 +13512,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
|
||
|
@@ -13571,23 +13572,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)",
|
||
|
diff --git a/src/nm-config.c b/src/nm-config.c
|
||
|
index c344d5cd1..771d74f2a 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 {
|
||
|
@@ -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;
|
||
|
+ 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;
|
||
|
+ }
|
||
|
|
||
|
- normalized = nm_utils_hwaddr_canonical (perm_hw_addr_fake, -1);
|
||
|
- g_free (perm_hw_addr_fake);
|
||
|
- perm_hw_addr_fake = normalized;
|
||
|
- }
|
||
|
+ 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;
|
||
|
|
||
|
- nm_owned = nm_config_keyfile_get_boolean (kf,
|
||
|
- DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||
|
- DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED,
|
||
|
- -1);
|
||
|
+ 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)
|
||
|
{
|
||
|
diff --git a/src/nm-config.h b/src/nm-config.h
|
||
|
index 5b2dc65c4..52a4099b2 100644
|
||
|
--- a/src/nm-config.h
|
||
|
+++ b/src/nm-config.h
|
||
|
@@ -224,6 +224,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,
|
||
|
@@ -231,6 +232,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__ */
|
||
|
diff --git a/src/nm-manager.c b/src/nm-manager.c
|
||
|
index 7f1b9a9d9..9e5f7ad4c 100644
|
||
|
--- a/src/nm-manager.c
|
||
|
+++ b/src/nm-manager.c
|
||
|
@@ -2640,10 +2640,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,
|
||
|
--
|
||
|
2.14.3
|
||
|
|
||
|
|
||
|
From e6d73154f23bdd6e0c4e9b52a9ea64bd3c1d8a13 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Wed, 6 Dec 2017 15:51:18 +0100
|
||
|
Subject: [PATCH 4/7] core: add read/write support for route-metric to
|
||
|
NMConfig's device state
|
||
|
|
||
|
(cherry picked from commit a90b523a3e09f68d5700e73981ba84d40e4682a5)
|
||
|
(cherry picked from commit 282ed0d17501fda8b8c30020c029eb86f364e8bc)
|
||
|
---
|
||
|
src/nm-config.c | 29 ++++++++++++++++++++++++-----
|
||
|
src/nm-config.h | 9 +++++++--
|
||
|
src/nm-manager.c | 6 +++++-
|
||
|
3 files changed, 36 insertions(+), 8 deletions(-)
|
||
|
|
||
|
diff --git a/src/nm-config.c b/src/nm-config.c
|
||
|
index 771d74f2a..97ae3f6f4 100644
|
||
|
--- a/src/nm-config.c
|
||
|
+++ b/src/nm-config.c
|
||
|
@@ -1933,6 +1933,7 @@ _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 "route-metric-default"
|
||
|
|
||
|
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType,
|
||
|
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
|
||
|
@@ -1952,6 +1953,7 @@ _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;
|
||
|
|
||
|
nm_assert (kf);
|
||
|
nm_assert (ifindex > 0);
|
||
|
@@ -1992,6 +1994,13 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf)
|
||
|
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 = nm_config_keyfile_get_int64 (kf,
|
||
|
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||
|
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT,
|
||
|
+ 10, 1, G_MAXUINT32, 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;
|
||
|
|
||
|
@@ -2004,6 +2013,7 @@ _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 = route_metric_default;
|
||
|
|
||
|
p = (char *) (&device_state[1]);
|
||
|
if (connection_uuid) {
|
||
|
@@ -2048,13 +2058,14 @@ nm_config_device_state_load (int ifindex)
|
||
|
", 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,
|
||
|
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);
|
||
|
|
||
|
return device_state;
|
||
|
}
|
||
|
@@ -2107,7 +2118,8 @@ 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)
|
||
|
{
|
||
|
char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
|
||
|
GError *local = NULL;
|
||
|
@@ -2149,17 +2161,24 @@ nm_config_device_state_write (int ifindex,
|
||
|
nm_owned);
|
||
|
}
|
||
|
|
||
|
+ if (route_metric_default != 0) {
|
||
|
+ g_key_file_set_int64 (kf,
|
||
|
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||
|
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT,
|
||
|
+ route_metric_default);
|
||
|
+ }
|
||
|
|
||
|
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,
|
||
|
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);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
diff --git a/src/nm-config.h b/src/nm-config.h
|
||
|
index 52a4099b2..4c6fcca2b 100644
|
||
|
--- a/src/nm-config.h
|
||
|
+++ b/src/nm-config.h
|
||
|
@@ -212,6 +212,9 @@ struct _NMConfigDeviceStateData {
|
||
|
int ifindex;
|
||
|
NMConfigDeviceStateManagedType managed;
|
||
|
|
||
|
+ /* a value of zero means that no metric is set. */
|
||
|
+ guint32 route_metric_default;
|
||
|
+
|
||
|
/* the UUID of the last settings-connection active
|
||
|
* on the device. */
|
||
|
const char *connection_uuid;
|
||
|
@@ -220,7 +223,7 @@ struct _NMConfigDeviceStateData {
|
||
|
|
||
|
/* whether the device was nm-owned (0/1) or -1 for
|
||
|
* non-software devices. */
|
||
|
- gint nm_owned;
|
||
|
+ int nm_owned:3;
|
||
|
};
|
||
|
|
||
|
NMConfigDeviceStateData *nm_config_device_state_load (int ifindex);
|
||
|
@@ -229,7 +232,9 @@ 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);
|
||
|
+
|
||
|
void nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes);
|
||
|
|
||
|
const GHashTable *nm_config_device_state_get_all (NMConfig *self);
|
||
|
diff --git a/src/nm-manager.c b/src/nm-manager.c
|
||
|
index 9e5f7ad4c..8b0b8013b 100644
|
||
|
--- a/src/nm-manager.c
|
||
|
+++ b/src/nm-manager.c
|
||
|
@@ -5198,6 +5198,7 @@ nm_manager_write_device_state (NMManager *self)
|
||
|
const char *uuid = NULL;
|
||
|
const char *perm_hw_addr_fake = NULL;
|
||
|
gboolean perm_hw_addr_is_fake;
|
||
|
+ guint32 route_metric_default;
|
||
|
|
||
|
ifindex = nm_device_get_ip_ifindex (device);
|
||
|
if (ifindex <= 0)
|
||
|
@@ -5227,11 +5228,14 @@ nm_manager_write_device_state (NMManager *self)
|
||
|
|
||
|
nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1;
|
||
|
|
||
|
+ route_metric_default = 0;
|
||
|
+
|
||
|
if (nm_config_device_state_write (ifindex,
|
||
|
managed_type,
|
||
|
perm_hw_addr_fake,
|
||
|
uuid,
|
||
|
- nm_owned))
|
||
|
+ nm_owned,
|
||
|
+ route_metric_default))
|
||
|
g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex));
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.14.3
|
||
|
|
||
|
|
||
|
From 747eb4bbb0f69f106e857e37256f26770bd9d518 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Tue, 5 Dec 2017 16:32:04 +0100
|
||
|
Subject: [PATCH 5/7] device: generate unique default route-metrics per
|
||
|
interface
|
||
|
|
||
|
In the past we had NMDefaultRouteManager which would coordinate adding
|
||
|
the default-route with identical metrics. That especially happened, when
|
||
|
activating two devices of the same type, without explicitly specifying
|
||
|
ipv4.route-metric. For example, with ethernet devices, the routes on
|
||
|
both interfaces would get a metric of 100.
|
||
|
|
||
|
Coordinating routes was especially necessary, because we added
|
||
|
routes with NLM_F_EXCL flag, akin to `ip route replace`. We not
|
||
|
only had to avoid that activating two devices in NetworkManager would
|
||
|
result in a fight over the default-route, but more importently
|
||
|
to preserve externally added default-routes on unmanaged interfaces.
|
||
|
|
||
|
NMDefaultRouteManager would ensure that in case of duplicate
|
||
|
metrics, that the device that activated first would keep the
|
||
|
best default-route. It would do so by bumping the metric
|
||
|
of the second device to find a unused metric. The bumping itself
|
||
|
was not very important -- MDefaultRouteManager could also just not
|
||
|
configure any default-routes that show up as second, the result
|
||
|
would be quite similar. More important was to keep the best
|
||
|
default-route on the first activating device until the device
|
||
|
deactivates or a device activates that really has a better
|
||
|
default-route..
|
||
|
|
||
|
Likewise, NMRouteManager would globally manage non-default-routes.
|
||
|
It would not do any bumping of metrics, but it would also ensure that the routes
|
||
|
of the device that activates first are not overwritten by a device activating
|
||
|
later.
|
||
|
|
||
|
However, the `ip route replace` approach has downsides, especially
|
||
|
that it messes with routes on other interfaces, interfaces that are
|
||
|
possibly not managed by NetworkManager. Another downside is, that
|
||
|
binding a socket to an interface might not result in correct
|
||
|
routes, because the route might just not be there (in case of
|
||
|
NMRouteManager, which wouldn't configure duplicate routes by bumping
|
||
|
their metric).
|
||
|
|
||
|
Since commit 77ec302714795f905301d500b9aab6c88001f32e we would no longer
|
||
|
use NLM_F_EXCL, but add routes akin to `ip route append`. When
|
||
|
activating for example two ethernet devices with no explict route
|
||
|
metric configuration, there are two routes like
|
||
|
|
||
|
default via 10.16.122.254 dev eth0 proto dhcp metric 100
|
||
|
default via 192.168.100.1 dev eth1 proto dhcp metric 100
|
||
|
|
||
|
This does not only affect default routes. In case of a multi-homing
|
||
|
setup you'd get
|
||
|
|
||
|
192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.1 metric 100
|
||
|
192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.1 metric 100
|
||
|
|
||
|
but it's visible the most for default-routes.
|
||
|
|
||
|
Note that we would append the routes that are activated later, as the order
|
||
|
of `ip route show` confirms. One might hence expect, that kernel selects
|
||
|
a route based on the order in the routing tables. However, that isn't
|
||
|
the case, and activating the second interface will non-deterministically
|
||
|
re-route traffic via the new interface. That will interfere badly with
|
||
|
with NAT, stateful firewalls, and existing connections (like TCP).
|
||
|
|
||
|
The solution is to have NMManager keep a global index of the default route-metrics
|
||
|
currently in use. So, instead of determining the default-route metric based solely
|
||
|
on the device-type, we now in addition generate default metrics that do not
|
||
|
overlap. For example, if you activate eth0 first, it gets route-metric 100,
|
||
|
and if you then activate eth1, it gets 101. Note that if you deactivate
|
||
|
and re-activate eth0, then it will get route-metric 102, because the
|
||
|
best route should stick on eth1 (which reserves the range 100 to 101).
|
||
|
|
||
|
Note that when a connection explititly selects a particular metric, then that
|
||
|
choice is honored (contrary to NMDefaultRouteManager which was more concerned
|
||
|
with avoiding conflicts, then keeping the exact metric).
|
||
|
|
||
|
https://bugzilla.redhat.com/show_bug.cgi?id=1505893
|
||
|
(cherry picked from commit 6a32c64d8fb2a9c1cfb78ab7e2f0bb3a269c81d7)
|
||
|
(cherry picked from commit bd2d71754b770b43a71d85ca5f79832bbdb6b77a)
|
||
|
---
|
||
|
src/devices/nm-device.c | 10 +-
|
||
|
src/nm-manager.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||
|
src/nm-manager.h | 10 ++
|
||
|
3 files changed, 255 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
|
||
|
index 755589674..40c425a5b 100644
|
||
|
--- a/src/devices/nm-device.c
|
||
|
+++ b/src/devices/nm-device.c
|
||
|
@@ -1765,7 +1765,10 @@ nm_device_get_route_metric (NMDevice *self,
|
||
|
if (route_metric >= 0)
|
||
|
goto out;
|
||
|
}
|
||
|
- route_metric = nm_device_get_route_metric_default (nm_device_get_device_type (self));
|
||
|
+
|
||
|
+ route_metric = nm_manager_device_route_metric_reserve (nm_manager_get (),
|
||
|
+ nm_device_get_ip_ifindex (self),
|
||
|
+ nm_device_get_device_type (self));
|
||
|
out:
|
||
|
return nm_utils_ip_route_metric_normalize (addr_family, route_metric);
|
||
|
}
|
||
|
@@ -12482,6 +12485,11 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type)
|
||
|
|
||
|
_cancel_activation (self);
|
||
|
|
||
|
+ if (cleanup_type != CLEANUP_TYPE_KEEP) {
|
||
|
+ nm_manager_device_route_metric_clear (nm_manager_get (),
|
||
|
+ nm_device_get_ip_ifindex (self));
|
||
|
+ }
|
||
|
+
|
||
|
if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE
|
||
|
&& priv->fw_state >= FIREWALL_STATE_INITIALIZED
|
||
|
&& priv->fw_mgr
|
||
|
diff --git a/src/nm-manager.c b/src/nm-manager.c
|
||
|
index 8b0b8013b..4d3416b37 100644
|
||
|
--- a/src/nm-manager.c
|
||
|
+++ b/src/nm-manager.c
|
||
|
@@ -160,6 +160,8 @@ typedef struct {
|
||
|
|
||
|
NMAuthManager *auth_mgr;
|
||
|
|
||
|
+ GHashTable *device_route_metrics;
|
||
|
+
|
||
|
GSList *auth_chains;
|
||
|
GHashTable *sleep_devices;
|
||
|
|
||
|
@@ -324,6 +326,237 @@ static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
|
||
|
+typedef struct {
|
||
|
+ int ifindex;
|
||
|
+ guint32 aspired_metric;
|
||
|
+ guint32 effective_metric;
|
||
|
+} DeviceRouteMetricData;
|
||
|
+
|
||
|
+static DeviceRouteMetricData *
|
||
|
+_device_route_metric_data_new (int ifindex, guint32 metric)
|
||
|
+{
|
||
|
+ DeviceRouteMetricData *data;
|
||
|
+
|
||
|
+ nm_assert (ifindex > 0);
|
||
|
+
|
||
|
+ /* For IPv4, metrics can use the entire uint32 bit range. For IPv6,
|
||
|
+ * zero is treated like 1024. Since we handle IPv4 and IPv6 identically,
|
||
|
+ * we cannot allow a zero metric here.
|
||
|
+ */
|
||
|
+ nm_assert (metric > 0);
|
||
|
+
|
||
|
+ data = g_slice_new0 (DeviceRouteMetricData);
|
||
|
+ data->ifindex = ifindex;
|
||
|
+ data->aspired_metric = metric;
|
||
|
+ data->effective_metric = metric;
|
||
|
+ return data;
|
||
|
+}
|
||
|
+
|
||
|
+static guint
|
||
|
+_device_route_metric_data_by_ifindex_hash (gconstpointer p)
|
||
|
+{
|
||
|
+ const DeviceRouteMetricData *data = p;
|
||
|
+ NMHashState h;
|
||
|
+
|
||
|
+ nm_hash_init (&h, 1030338191);
|
||
|
+ nm_hash_update_vals (&h, data->ifindex);
|
||
|
+ return nm_hash_complete (&h);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+_device_route_metric_data_by_ifindex_equal (gconstpointer pa, gconstpointer pb)
|
||
|
+{
|
||
|
+ const DeviceRouteMetricData *a = pa;
|
||
|
+ const DeviceRouteMetricData *b = pb;
|
||
|
+
|
||
|
+ return a->ifindex == b->ifindex;
|
||
|
+}
|
||
|
+
|
||
|
+static guint32
|
||
|
+_device_route_metric_get (NMManager *self,
|
||
|
+ int ifindex,
|
||
|
+ NMDeviceType device_type,
|
||
|
+ gboolean lookup_only)
|
||
|
+{
|
||
|
+ NMManagerPrivate *priv;
|
||
|
+ const DeviceRouteMetricData *d2;
|
||
|
+ DeviceRouteMetricData *data;
|
||
|
+ DeviceRouteMetricData data_lookup;
|
||
|
+ const NMDedupMultiHeadEntry *all_links_head;
|
||
|
+ NMPObject links_needle;
|
||
|
+ guint n_links;
|
||
|
+ gboolean cleaned = FALSE;
|
||
|
+ GHashTableIter h_iter;
|
||
|
+
|
||
|
+ g_return_val_if_fail (NM_IS_MANAGER (self), 0);
|
||
|
+
|
||
|
+ if (ifindex <= 0) {
|
||
|
+ if (lookup_only)
|
||
|
+ return 0;
|
||
|
+ return nm_device_get_route_metric_default (device_type);
|
||
|
+ }
|
||
|
+
|
||
|
+ priv = NM_MANAGER_GET_PRIVATE (self);
|
||
|
+
|
||
|
+ if ( lookup_only
|
||
|
+ && !priv->device_route_metrics)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (G_UNLIKELY (!priv->device_route_metrics)) {
|
||
|
+ const GHashTable *h;
|
||
|
+ const NMConfigDeviceStateData *device_state;
|
||
|
+
|
||
|
+ priv->device_route_metrics = g_hash_table_new_full (_device_route_metric_data_by_ifindex_hash,
|
||
|
+ _device_route_metric_data_by_ifindex_equal,
|
||
|
+ NULL,
|
||
|
+ nm_g_slice_free_fcn (DeviceRouteMetricData));
|
||
|
+ cleaned = TRUE;
|
||
|
+
|
||
|
+ /* we need to pre-populate the cache for all (still existing) devices from the state-file */
|
||
|
+ h = nm_config_device_state_get_all (priv->config);
|
||
|
+ if (!h)
|
||
|
+ goto initited;
|
||
|
+
|
||
|
+ g_hash_table_iter_init (&h_iter, (GHashTable *) h);
|
||
|
+ while (g_hash_table_iter_next (&h_iter, NULL, (gpointer *) &device_state)) {
|
||
|
+ if (!device_state->route_metric_default)
|
||
|
+ continue;
|
||
|
+ if (!nm_platform_link_get (priv->platform, device_state->ifindex)) {
|
||
|
+ /* we have the entry in the state file, but (currently) no such
|
||
|
+ * ifindex exists in platform. Most likely the entry is obsolete,
|
||
|
+ * hence we skip it. */
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if (!nm_g_hash_table_add (priv->device_route_metrics,
|
||
|
+ _device_route_metric_data_new (device_state->ifindex,
|
||
|
+ device_state->route_metric_default)))
|
||
|
+ nm_assert_not_reached ();
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+initited:
|
||
|
+ data_lookup.ifindex = ifindex;
|
||
|
+
|
||
|
+ data = g_hash_table_lookup (priv->device_route_metrics, &data_lookup);
|
||
|
+ if (data)
|
||
|
+ return data->effective_metric;
|
||
|
+ if (lookup_only)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (!cleaned) {
|
||
|
+ /* get the number of all links in the platform cache. */
|
||
|
+ all_links_head = nm_platform_lookup_all (priv->platform,
|
||
|
+ NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||
|
+ nmp_object_stackinit_id_link (&links_needle, 1));
|
||
|
+ n_links = all_links_head ? all_links_head->len : 0;
|
||
|
+
|
||
|
+ /* on systems where a lot of devices are created and go away, the index contains
|
||
|
+ * a lot of stale entries. We must from time to time clean them up.
|
||
|
+ *
|
||
|
+ * Do do this cleanup, whenever we have more enties then 2 times the number of links. */
|
||
|
+ if (G_UNLIKELY (g_hash_table_size (priv->device_route_metrics) > NM_MAX (20, n_links * 2))) {
|
||
|
+ /* from time to time, we need to do some house-keeping and prune stale entries.
|
||
|
+ * Otherwise, on a system where interfaces frequently come and go (docker), we
|
||
|
+ * keep growing this cache for ifindexes that no longer exist. */
|
||
|
+ g_hash_table_iter_init (&h_iter, priv->device_route_metrics);
|
||
|
+ while (g_hash_table_iter_next (&h_iter, NULL, (gpointer *) &d2)) {
|
||
|
+ if (!nm_platform_link_get (priv->platform, d2->ifindex))
|
||
|
+ g_hash_table_iter_remove (&h_iter);
|
||
|
+ }
|
||
|
+ cleaned = TRUE;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ data = _device_route_metric_data_new (ifindex, nm_device_get_route_metric_default (device_type));
|
||
|
+
|
||
|
+ /* unfortunately, there is no stright forward way to lookup all reserved metrics.
|
||
|
+ * Note, that we don't only have to know which metrics are currently reserved,
|
||
|
+ * but also, which metrics are now seemingly un-used but caused another reserved
|
||
|
+ * metric to be bumped. Hence, the naive O(n^2) search :( */
|
||
|
+again:
|
||
|
+ g_hash_table_iter_init (&h_iter, priv->device_route_metrics);
|
||
|
+ while (g_hash_table_iter_next (&h_iter, NULL, (gpointer *) &d2)) {
|
||
|
+ if ( data->effective_metric < d2->aspired_metric
|
||
|
+ || data->effective_metric > d2->effective_metric) {
|
||
|
+ /* no overlap. Skip. */
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if ( !cleaned
|
||
|
+ && !nm_platform_link_get (priv->platform, d2->ifindex)) {
|
||
|
+ /* the metric seems taken, but there is no such interface. This entry
|
||
|
+ * is stale, forget about it. */
|
||
|
+ g_hash_table_iter_remove (&h_iter);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ data->effective_metric = d2->effective_metric;
|
||
|
+ if (data->effective_metric == G_MAXUINT32) {
|
||
|
+ /* we cannot bump any further. Done. */
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (data->effective_metric - data->aspired_metric > 50) {
|
||
|
+ /* as one active interface reserves an entire range of metrics
|
||
|
+ * (from aspired_metric to effective_metric), that means if you
|
||
|
+ * alternatingly activate two interfaces, their metric will
|
||
|
+ * juggle up.
|
||
|
+ *
|
||
|
+ * Limit this, don't bump the metric more then 50 times. */
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* bump the metric, and search again. */
|
||
|
+ data->effective_metric++;
|
||
|
+ goto again;
|
||
|
+ }
|
||
|
+
|
||
|
+ _LOGT (LOGD_DEVICE, "default-route-metric: ifindex %d reserves metric %u (aspired %u)",
|
||
|
+ data->ifindex, data->effective_metric, data->aspired_metric);
|
||
|
+
|
||
|
+ if (!nm_g_hash_table_add (priv->device_route_metrics, data))
|
||
|
+ nm_assert_not_reached ();
|
||
|
+
|
||
|
+ return data->effective_metric;
|
||
|
+}
|
||
|
+
|
||
|
+guint32
|
||
|
+nm_manager_device_route_metric_reserve (NMManager *self,
|
||
|
+ int ifindex,
|
||
|
+ NMDeviceType device_type)
|
||
|
+{
|
||
|
+ guint32 metric;
|
||
|
+
|
||
|
+ metric = _device_route_metric_get (self, ifindex, device_type, FALSE);
|
||
|
+ nm_assert (metric != 0);
|
||
|
+ return metric;
|
||
|
+}
|
||
|
+
|
||
|
+guint32
|
||
|
+nm_manager_device_route_metric_get (NMManager *self,
|
||
|
+ int ifindex)
|
||
|
+{
|
||
|
+ return _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, TRUE);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+nm_manager_device_route_metric_clear (NMManager *self,
|
||
|
+ int ifindex)
|
||
|
+{
|
||
|
+ NMManagerPrivate *priv;
|
||
|
+ DeviceRouteMetricData data_lookup;
|
||
|
+
|
||
|
+ priv = NM_MANAGER_GET_PRIVATE (self);
|
||
|
+
|
||
|
+ if (!priv->device_route_metrics)
|
||
|
+ return;
|
||
|
+ data_lookup.ifindex = ifindex;
|
||
|
+ if (g_hash_table_remove (priv->device_route_metrics, &data_lookup)) {
|
||
|
+ _LOGT (LOGD_DEVICE, "default-route-metric: ifindex %d released",
|
||
|
+ ifindex);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/*****************************************************************************/
|
||
|
+
|
||
|
static void
|
||
|
_delete_volatile_connection_do (NMManager *self,
|
||
|
NMSettingsConnection *connection)
|
||
|
@@ -5228,7 +5461,7 @@ nm_manager_write_device_state (NMManager *self)
|
||
|
|
||
|
nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1;
|
||
|
|
||
|
- route_metric_default = 0;
|
||
|
+ route_metric_default = nm_manager_device_route_metric_get (self, ifindex);
|
||
|
|
||
|
if (nm_config_device_state_write (ifindex,
|
||
|
managed_type,
|
||
|
@@ -6607,6 +6840,8 @@ dispose (GObject *object)
|
||
|
|
||
|
nm_clear_g_source (&priv->timestamp_update_id);
|
||
|
|
||
|
+ g_clear_pointer (&priv->device_route_metrics, g_hash_table_destroy);
|
||
|
+
|
||
|
G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
|
||
|
}
|
||
|
|
||
|
diff --git a/src/nm-manager.h b/src/nm-manager.h
|
||
|
index 2d463c718..d82570889 100644
|
||
|
--- a/src/nm-manager.h
|
||
|
+++ b/src/nm-manager.h
|
||
|
@@ -114,6 +114,16 @@ NMDevice * nm_manager_get_device_by_ifindex (NMManager *manager,
|
||
|
NMDevice * nm_manager_get_device_by_path (NMManager *manager,
|
||
|
const char *path);
|
||
|
|
||
|
+guint32 nm_manager_device_route_metric_reserve (NMManager *self,
|
||
|
+ int ifindex,
|
||
|
+ NMDeviceType device_type);
|
||
|
+
|
||
|
+guint32 nm_manager_device_route_metric_get (NMManager *self,
|
||
|
+ int ifindex);
|
||
|
+
|
||
|
+void nm_manager_device_route_metric_clear (NMManager *self,
|
||
|
+ int ifindex);
|
||
|
+
|
||
|
char * nm_manager_get_connection_iface (NMManager *self,
|
||
|
NMConnection *connection,
|
||
|
NMDevice **out_parent,
|
||
|
--
|
||
|
2.14.3
|
||
|
|
||
|
|
||
|
From f1728bdeac80fdc45ed969b8821a207383962296 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Tue, 19 Dec 2017 10:10:15 +0100
|
||
|
Subject: [PATCH 6/7] core: ensure that the default route-metric bumps at most
|
||
|
50 points
|
||
|
|
||
|
First check that the limit of 50 metric points is not surpassed.
|
||
|
Otherwise, if you have an ethernet device (aspired 100, effective
|
||
|
130) and a MACSec devic (aspired 125, effective 155), activating a
|
||
|
new ethernet device would bump it's metric to 155 -- more then
|
||
|
the 50 points limit.
|
||
|
|
||
|
It doesn't matter too much, because the cases where the limit of
|
||
|
50 could have been surpassed were very specific. Still, change
|
||
|
it to ensure that the limit is always honored as one would expect.
|
||
|
|
||
|
Fixes: 6a32c64d8fb2a9c1cfb78ab7e2f0bb3a269c81d7
|
||
|
(cherry picked from commit 2499d3bdc6007308bf282cb44462990a4cd03b0e)
|
||
|
(cherry picked from commit 5fd91fb67d3e3865545f5cbc1f39292635440cd3)
|
||
|
---
|
||
|
src/nm-manager.c | 26 ++++++++++++++++++--------
|
||
|
1 file changed, 18 insertions(+), 8 deletions(-)
|
||
|
|
||
|
diff --git a/src/nm-manager.c b/src/nm-manager.c
|
||
|
index 4d3416b37..fad4f64b8 100644
|
||
|
--- a/src/nm-manager.c
|
||
|
+++ b/src/nm-manager.c
|
||
|
@@ -472,7 +472,11 @@ initited:
|
||
|
/* unfortunately, there is no stright forward way to lookup all reserved metrics.
|
||
|
* Note, that we don't only have to know which metrics are currently reserved,
|
||
|
* but also, which metrics are now seemingly un-used but caused another reserved
|
||
|
- * metric to be bumped. Hence, the naive O(n^2) search :( */
|
||
|
+ * metric to be bumped. Hence, the naive O(n^2) search :(
|
||
|
+ *
|
||
|
+ * Well, technically, since we limit bumping the metric to 50, this entire
|
||
|
+ * loop runs at most 50 times, so it's still O(n). Let's just say, it's not
|
||
|
+ * very efficient. */
|
||
|
again:
|
||
|
g_hash_table_iter_init (&h_iter, priv->device_route_metrics);
|
||
|
while (g_hash_table_iter_next (&h_iter, NULL, (gpointer *) &d2)) {
|
||
|
@@ -488,24 +492,30 @@ again:
|
||
|
g_hash_table_iter_remove (&h_iter);
|
||
|
continue;
|
||
|
}
|
||
|
- data->effective_metric = d2->effective_metric;
|
||
|
- if (data->effective_metric == G_MAXUINT32) {
|
||
|
- /* we cannot bump any further. Done. */
|
||
|
+
|
||
|
+ if (d2->effective_metric == G_MAXUINT32) {
|
||
|
+ /* we cannot bump the metric any further. Done.
|
||
|
+ *
|
||
|
+ * Actually, this can currently not happen because the aspired_metric
|
||
|
+ * are small numbers and we limit the bumping to 50. Still, for
|
||
|
+ * completeness... */
|
||
|
+ data->effective_metric = G_MAXUINT32;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- if (data->effective_metric - data->aspired_metric > 50) {
|
||
|
+ if (d2->effective_metric - data->aspired_metric >= 50) {
|
||
|
/* as one active interface reserves an entire range of metrics
|
||
|
* (from aspired_metric to effective_metric), that means if you
|
||
|
* alternatingly activate two interfaces, their metric will
|
||
|
- * juggle up.
|
||
|
+ * bump each other.
|
||
|
*
|
||
|
- * Limit this, don't bump the metric more then 50 times. */
|
||
|
+ * Limit this, bump the metric at most 50 points. */
|
||
|
+ data->effective_metric = data->aspired_metric + 50;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* bump the metric, and search again. */
|
||
|
- data->effective_metric++;
|
||
|
+ data->effective_metric = d2->effective_metric + 1;
|
||
|
goto again;
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.14.3
|
||
|
|
||
|
|
||
|
From a245f5eb91e8c30ae19403586f5ef9c14ef5f6d2 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Haller <thaller@redhat.com>
|
||
|
Date: Wed, 20 Dec 2017 12:45:02 +0100
|
||
|
Subject: [PATCH 7/7] core: persist aspired default route-metric in device's
|
||
|
state file
|
||
|
|
||
|
NMManager tries to assign unique route-metrics in an increasing manner
|
||
|
so that the device which activates first keeps to have the best routes.
|
||
|
|
||
|
This information is also persisted in the device's state file, however
|
||
|
we not only need to persist the effective route-metric which was
|
||
|
eventually chosen by NMManager, but also the aspired metric.
|
||
|
|
||
|
The reason is that when a metric is chosen for a device, the entire
|
||
|
range between aspired and effective route-metric is reserved for that
|
||
|
device. We must remember the entire range so that after restart the
|
||
|
entire range is still considered to be in use.
|
||
|
|
||
|
Fixes: 6a32c64d8fb2a9c1cfb78ab7e2f0bb3a269c81d7
|
||
|
(cherry picked from commit 4277bc0ee0479ad62369c3a261ea8d098e5e25ad)
|
||
|
(cherry picked from commit fa53c715d1b929516e5e32e13ebc630a2c339394)
|
||
|
---
|
||
|
src/nm-config.c | 50 +++++++++++++++++++++++++++++++++++---------------
|
||
|
src/nm-config.h | 6 ++++--
|
||
|
src/nm-manager.c | 48 +++++++++++++++++++++++++++---------------------
|
||
|
src/nm-manager.h | 3 ---
|
||
|
4 files changed, 66 insertions(+), 41 deletions(-)
|
||
|
|
||
|
diff --git a/src/nm-config.c b/src/nm-config.c
|
||
|
index 97ae3f6f4..29f0d5177 100644
|
||
|
--- a/src/nm-config.c
|
||
|
+++ b/src/nm-config.c
|
||
|
@@ -1933,7 +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 "route-metric-default"
|
||
|
+#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"),
|
||
|
@@ -1953,7 +1954,8 @@ _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;
|
||
|
+ guint32 route_metric_default_effective;
|
||
|
+ guint32 route_metric_default_aspired;
|
||
|
|
||
|
nm_assert (kf);
|
||
|
nm_assert (ifindex > 0);
|
||
|
@@ -1996,10 +1998,18 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf)
|
||
|
|
||
|
/* 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 = nm_config_keyfile_get_int64 (kf,
|
||
|
- DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
|
||
|
- DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT,
|
||
|
- 10, 1, G_MAXUINT32, 0);
|
||
|
+ 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;
|
||
|
@@ -2013,7 +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 = route_metric_default;
|
||
|
+ 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) {
|
||
|
@@ -2058,14 +2069,15 @@ nm_config_device_state_load (int ifindex)
|
||
|
", 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, route-metric-default=%"G_GUINT32_FORMAT,
|
||
|
+ _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,
|
||
|
- device_state->route_metric_default);
|
||
|
+ device_state->route_metric_default_aspired,
|
||
|
+ device_state->route_metric_default_effective);
|
||
|
|
||
|
return device_state;
|
||
|
}
|
||
|
@@ -2119,7 +2131,8 @@ nm_config_device_state_write (int ifindex,
|
||
|
const char *perm_hw_addr_fake,
|
||
|
const char *connection_uuid,
|
||
|
gint nm_owned,
|
||
|
- guint32 route_metric_default)
|
||
|
+ guint32 route_metric_default_aspired,
|
||
|
+ guint32 route_metric_default_effective)
|
||
|
{
|
||
|
char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
|
||
|
GError *local = NULL;
|
||
|
@@ -2161,11 +2174,17 @@ nm_config_device_state_write (int ifindex,
|
||
|
nm_owned);
|
||
|
}
|
||
|
|
||
|
- if (route_metric_default != 0) {
|
||
|
+ 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,
|
||
|
- route_metric_default);
|
||
|
+ 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)) {
|
||
|
@@ -2173,12 +2192,13 @@ nm_config_device_state_write (int ifindex,
|
||
|
g_error_free (local);
|
||
|
return FALSE;
|
||
|
}
|
||
|
- _LOGT ("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s, route-metric-default=%"G_GUINT32_FORMAT,
|
||
|
+ _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, "", ""),
|
||
|
- route_metric_default);
|
||
|
+ route_metric_default_aspired,
|
||
|
+ route_metric_default_effective);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
diff --git a/src/nm-config.h b/src/nm-config.h
|
||
|
index 4c6fcca2b..42ab4682d 100644
|
||
|
--- a/src/nm-config.h
|
||
|
+++ b/src/nm-config.h
|
||
|
@@ -213,7 +213,8 @@ struct _NMConfigDeviceStateData {
|
||
|
NMConfigDeviceStateManagedType managed;
|
||
|
|
||
|
/* a value of zero means that no metric is set. */
|
||
|
- guint32 route_metric_default;
|
||
|
+ guint32 route_metric_default_aspired;
|
||
|
+ guint32 route_metric_default_effective;
|
||
|
|
||
|
/* the UUID of the last settings-connection active
|
||
|
* on the device. */
|
||
|
@@ -233,7 +234,8 @@ gboolean nm_config_device_state_write (int ifindex,
|
||
|
const char *perm_hw_addr_fake,
|
||
|
const char *connection_uuid,
|
||
|
gint nm_owned,
|
||
|
- guint32 route_metric_default);
|
||
|
+ guint32 route_metric_default_aspired,
|
||
|
+ guint32 route_metric_default_effective);
|
||
|
|
||
|
void nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes);
|
||
|
|
||
|
diff --git a/src/nm-manager.c b/src/nm-manager.c
|
||
|
index fad4f64b8..c011bfd0e 100644
|
||
|
--- a/src/nm-manager.c
|
||
|
+++ b/src/nm-manager.c
|
||
|
@@ -333,7 +333,7 @@ typedef struct {
|
||
|
} DeviceRouteMetricData;
|
||
|
|
||
|
static DeviceRouteMetricData *
|
||
|
-_device_route_metric_data_new (int ifindex, guint32 metric)
|
||
|
+_device_route_metric_data_new (int ifindex, guint32 aspired_metric, guint32 effective_metric)
|
||
|
{
|
||
|
DeviceRouteMetricData *data;
|
||
|
|
||
|
@@ -343,12 +343,13 @@ _device_route_metric_data_new (int ifindex, guint32 metric)
|
||
|
* zero is treated like 1024. Since we handle IPv4 and IPv6 identically,
|
||
|
* we cannot allow a zero metric here.
|
||
|
*/
|
||
|
- nm_assert (metric > 0);
|
||
|
+ nm_assert (aspired_metric > 0);
|
||
|
+ nm_assert (effective_metric == 0 || aspired_metric <= effective_metric);
|
||
|
|
||
|
data = g_slice_new0 (DeviceRouteMetricData);
|
||
|
data->ifindex = ifindex;
|
||
|
- data->aspired_metric = metric;
|
||
|
- data->effective_metric = metric;
|
||
|
+ data->aspired_metric = aspired_metric;
|
||
|
+ data->effective_metric = effective_metric ?: aspired_metric;
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
@@ -376,7 +377,8 @@ static guint32
|
||
|
_device_route_metric_get (NMManager *self,
|
||
|
int ifindex,
|
||
|
NMDeviceType device_type,
|
||
|
- gboolean lookup_only)
|
||
|
+ gboolean lookup_only,
|
||
|
+ guint32 *out_aspired_metric)
|
||
|
{
|
||
|
NMManagerPrivate *priv;
|
||
|
const DeviceRouteMetricData *d2;
|
||
|
@@ -387,13 +389,18 @@ _device_route_metric_get (NMManager *self,
|
||
|
guint n_links;
|
||
|
gboolean cleaned = FALSE;
|
||
|
GHashTableIter h_iter;
|
||
|
+ guint32 metric;
|
||
|
|
||
|
g_return_val_if_fail (NM_IS_MANAGER (self), 0);
|
||
|
|
||
|
+ NM_SET_OUT (out_aspired_metric, 0);
|
||
|
+
|
||
|
if (ifindex <= 0) {
|
||
|
if (lookup_only)
|
||
|
return 0;
|
||
|
- return nm_device_get_route_metric_default (device_type);
|
||
|
+ metric = nm_device_get_route_metric_default (device_type);
|
||
|
+ NM_SET_OUT (out_aspired_metric, metric);
|
||
|
+ return metric;
|
||
|
}
|
||
|
|
||
|
priv = NM_MANAGER_GET_PRIVATE (self);
|
||
|
@@ -419,7 +426,7 @@ _device_route_metric_get (NMManager *self,
|
||
|
|
||
|
g_hash_table_iter_init (&h_iter, (GHashTable *) h);
|
||
|
while (g_hash_table_iter_next (&h_iter, NULL, (gpointer *) &device_state)) {
|
||
|
- if (!device_state->route_metric_default)
|
||
|
+ if (!device_state->route_metric_default_effective)
|
||
|
continue;
|
||
|
if (!nm_platform_link_get (priv->platform, device_state->ifindex)) {
|
||
|
/* we have the entry in the state file, but (currently) no such
|
||
|
@@ -429,7 +436,8 @@ _device_route_metric_get (NMManager *self,
|
||
|
}
|
||
|
if (!nm_g_hash_table_add (priv->device_route_metrics,
|
||
|
_device_route_metric_data_new (device_state->ifindex,
|
||
|
- device_state->route_metric_default)))
|
||
|
+ device_state->route_metric_default_aspired,
|
||
|
+ device_state->route_metric_default_effective)))
|
||
|
nm_assert_not_reached ();
|
||
|
}
|
||
|
}
|
||
|
@@ -439,7 +447,7 @@ initited:
|
||
|
|
||
|
data = g_hash_table_lookup (priv->device_route_metrics, &data_lookup);
|
||
|
if (data)
|
||
|
- return data->effective_metric;
|
||
|
+ goto out;
|
||
|
if (lookup_only)
|
||
|
return 0;
|
||
|
|
||
|
@@ -467,7 +475,7 @@ initited:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- data = _device_route_metric_data_new (ifindex, nm_device_get_route_metric_default (device_type));
|
||
|
+ data = _device_route_metric_data_new (ifindex, nm_device_get_route_metric_default (device_type), 0);
|
||
|
|
||
|
/* unfortunately, there is no stright forward way to lookup all reserved metrics.
|
||
|
* Note, that we don't only have to know which metrics are currently reserved,
|
||
|
@@ -525,6 +533,8 @@ again:
|
||
|
if (!nm_g_hash_table_add (priv->device_route_metrics, data))
|
||
|
nm_assert_not_reached ();
|
||
|
|
||
|
+out:
|
||
|
+ NM_SET_OUT (out_aspired_metric, data->aspired_metric);
|
||
|
return data->effective_metric;
|
||
|
}
|
||
|
|
||
|
@@ -535,18 +545,11 @@ nm_manager_device_route_metric_reserve (NMManager *self,
|
||
|
{
|
||
|
guint32 metric;
|
||
|
|
||
|
- metric = _device_route_metric_get (self, ifindex, device_type, FALSE);
|
||
|
+ metric = _device_route_metric_get (self, ifindex, device_type, FALSE, NULL);
|
||
|
nm_assert (metric != 0);
|
||
|
return metric;
|
||
|
}
|
||
|
|
||
|
-guint32
|
||
|
-nm_manager_device_route_metric_get (NMManager *self,
|
||
|
- int ifindex)
|
||
|
-{
|
||
|
- return _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, TRUE);
|
||
|
-}
|
||
|
-
|
||
|
void
|
||
|
nm_manager_device_route_metric_clear (NMManager *self,
|
||
|
int ifindex)
|
||
|
@@ -5441,7 +5444,8 @@ nm_manager_write_device_state (NMManager *self)
|
||
|
const char *uuid = NULL;
|
||
|
const char *perm_hw_addr_fake = NULL;
|
||
|
gboolean perm_hw_addr_is_fake;
|
||
|
- guint32 route_metric_default;
|
||
|
+ guint32 route_metric_default_aspired;
|
||
|
+ guint32 route_metric_default_effective;
|
||
|
|
||
|
ifindex = nm_device_get_ip_ifindex (device);
|
||
|
if (ifindex <= 0)
|
||
|
@@ -5471,14 +5475,16 @@ nm_manager_write_device_state (NMManager *self)
|
||
|
|
||
|
nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1;
|
||
|
|
||
|
- route_metric_default = nm_manager_device_route_metric_get (self, ifindex);
|
||
|
+ route_metric_default_effective = _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN,
|
||
|
+ TRUE, &route_metric_default_aspired);
|
||
|
|
||
|
if (nm_config_device_state_write (ifindex,
|
||
|
managed_type,
|
||
|
perm_hw_addr_fake,
|
||
|
uuid,
|
||
|
nm_owned,
|
||
|
- route_metric_default))
|
||
|
+ route_metric_default_aspired,
|
||
|
+ route_metric_default_effective))
|
||
|
g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex));
|
||
|
}
|
||
|
|
||
|
diff --git a/src/nm-manager.h b/src/nm-manager.h
|
||
|
index d82570889..b4587e088 100644
|
||
|
--- a/src/nm-manager.h
|
||
|
+++ b/src/nm-manager.h
|
||
|
@@ -118,9 +118,6 @@ guint32 nm_manager_device_route_metric_reserve (NMManager *self,
|
||
|
int ifindex,
|
||
|
NMDeviceType device_type);
|
||
|
|
||
|
-guint32 nm_manager_device_route_metric_get (NMManager *self,
|
||
|
- int ifindex);
|
||
|
-
|
||
|
void nm_manager_device_route_metric_clear (NMManager *self,
|
||
|
int ifindex);
|
||
|
|
||
|
--
|
||
|
2.14.3
|