From b54c16dfd2b4adaa3245898035d9476ad6c97fa1 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 02 2017 15:24:06 +0000 Subject: import NetworkManager-1.4.0-17.el7_3 --- diff --git a/SOURCES/0024-master-name-uuid-rh1369008.patch b/SOURCES/0024-master-name-uuid-rh1369008.patch new file mode 100644 index 0000000..92b5dcf --- /dev/null +++ b/SOURCES/0024-master-name-uuid-rh1369008.patch @@ -0,0 +1,342 @@ +From b28b275c5e6c36bf7b63ed9ab7b99505de61bf98 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 28 Nov 2016 12:32:03 +0000 +Subject: [PATCH] ifcfg-rh: write the master device name even if the master + property is an UUID + +We used MASTER, BRIDGE and TEAM_MASTER keys for a differnet purpose than the +network.service did, confusing the legacy tooling. Let's do our best to write +compatible configuration files: + +* Add *_UUID properties that won't clash with initscripts +* Ignore non-*_UUID keys on read if *_UUID is present +* If the connection.master is an UUID of a connection with a + connection.interface-name, write the uuid into the *_UUID key while setting + the non-*_UUID key to the interface name for compatibility + +https://bugzilla.redhat.com/show_bug.cgi?id=1369091 +(cherry picked from commit 8b7b0d3fc2604a2cdecb32d97f8cb3ff63a069f0) +--- + libnm-core/nm-setting-connection.c | 14 +++++++----- + src/nm-manager.c | 24 +++++++++++++++++++++ + src/nm-manager.h | 3 +++ + src/settings/plugins/ifcfg-rh/reader.c | 18 ++++++++++++---- + src/settings/plugins/ifcfg-rh/writer.c | 39 +++++++++++++++++++++++++--------- + 5 files changed, 79 insertions(+), 19 deletions(-) + +diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c +index f6b801c..a0a679e 100644 +--- a/libnm-core/nm-setting-connection.c ++++ b/libnm-core/nm-setting-connection.c +@@ -1650,9 +1650,11 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) + **/ + /* ---ifcfg-rh--- + * property: master +- * variable: MASTER, TEAM_MASTER, BRIDGE ++ * variable: MASTER, MASTER_UUID, TEAM_MASTER, TEAM_MASTER_UUID, BRIDGE, BRIDGE_UUID + * description: Reference to master connection. The variable used depends on +- * the connection type. ++ * the connection type and the value. In general, if the *_UUID variant is present, ++ * the variant without *_UUID is ignored. NetworkManager attempts to write both ++ * for compatibility with legacy tooling. + * ---end--- + */ + g_object_class_install_property +@@ -1673,10 +1675,12 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) + **/ + /* ---ifcfg-rh--- + * property: slave-type +- * variable: MASTER, TEAM_MASTER, DEVICETYPE, BRIDGE ++ * variable: MASTER, MASTER_UUID, TEAM_MASTER, TEAM_MASTER_UUID, DEVICETYPE, ++ * BRIDGE, BRIDGE_UUID + * description: Slave type doesn't map directly to a variable, but it is +- * recognized using different variables. MASTER for bonding, +- * TEAM_MASTER and DEVICETYPE for teaming, BRIDGE for bridging. ++ * recognized using different variables. MASTER and MASTER_UUID for bonding, ++ * TEAM_MASTER, TEAM_MASTER_UUID and DEVICETYPE for teaming, BRIDGE ++ * and BRIDGE_UUID for bridging. + * ---end--- + */ + g_object_class_install_property +diff --git a/src/nm-manager.c b/src/nm-manager.c +index c3d65cd..964c18a 100644 +--- a/src/nm-manager.c ++++ b/src/nm-manager.c +@@ -1135,6 +1135,30 @@ nm_manager_get_connection_iface (NMManager *self, + } + + /** ++ * nm_manager_iface_for_uuid: ++ * @self: the #NMManager ++ * @uuid: the connection uuid ++ * ++ * Gets a link name for the given UUID. Useful for the settings plugins that ++ * wish to write configuration files compatible with tooling that can't ++ * interpret our UUIDs. ++ * ++ * Returns: An interface name; %NULL if none matches ++ */ ++const char * ++nm_manager_iface_for_uuid (NMManager *self, const char *uuid) ++{ ++ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); ++ NMSettingsConnection *connection; ++ ++ connection = nm_settings_get_connection_by_uuid (priv->settings, uuid); ++ if (!connection) ++ return NULL; ++ ++ return nm_connection_get_interface_name (NM_CONNECTION (connection)); ++} ++ ++/** + * system_create_virtual_device: + * @self: the #NMManager + * @connection: the connection which might require a virtual device +diff --git a/src/nm-manager.h b/src/nm-manager.h +index d7aabff..ce3fa5a 100644 +--- a/src/nm-manager.h ++++ b/src/nm-manager.h +@@ -99,6 +99,9 @@ char * nm_manager_get_connection_iface (NMManager *self, + NMDevice **out_parent, + GError **error); + ++const char * nm_manager_iface_for_uuid (NMManager *self, ++ const char *uuid); ++ + NMActiveConnection *nm_manager_activate_connection (NMManager *manager, + NMSettingsConnection *connection, + const char *specific_object, +diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c +index 5a351cf..825d51e 100644 +--- a/src/settings/plugins/ifcfg-rh/reader.c ++++ b/src/settings/plugins/ifcfg-rh/reader.c +@@ -227,7 +227,9 @@ make_connection_setting (const char *file, + g_strfreev (items); + } + +- value = svGetValue (ifcfg, "BRIDGE", FALSE); ++ value = svGetValue (ifcfg, "BRIDGE_UUID", FALSE); ++ if (!value) ++ value = svGetValue (ifcfg, "BRIDGE", FALSE); + if (value) { + const char *old_value; + +@@ -1607,7 +1609,10 @@ check_if_bond_slave (shvarFile *ifcfg, + { + char *value; + +- value = svGetValue (ifcfg, "MASTER", FALSE); ++ value = svGetValue (ifcfg, "MASTER_UUID", FALSE); ++ if (!value) ++ value = svGetValue (ifcfg, "MASTER", FALSE); ++ + if (value) { + g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL); + g_object_set (s_con, +@@ -1627,9 +1632,12 @@ check_if_team_slave (shvarFile *ifcfg, + { + gs_free char *value = NULL; + +- value = svGetValue (ifcfg, "TEAM_MASTER", FALSE); ++ value = svGetValue (ifcfg, "TEAM_MASTER_UUID", FALSE); ++ if (!value) ++ value = svGetValue (ifcfg, "TEAM_MASTER", FALSE); + if (!value) + return FALSE; ++ + g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL); + g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL); + return TRUE; +@@ -4563,7 +4571,9 @@ make_bridge_port_setting (shvarFile *ifcfg) + + g_return_val_if_fail (ifcfg != NULL, FALSE); + +- value = svGetValue (ifcfg, "BRIDGE", FALSE); ++ value = svGetValue (ifcfg, "BRIDGE_UUID", FALSE); ++ if (!value) ++ value = svGetValue (ifcfg, "BRIDGE", FALSE); + if (value) { + g_free (value); + +diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c +index dcc48f2..dff8f1b 100644 +--- a/src/settings/plugins/ifcfg-rh/writer.c ++++ b/src/settings/plugins/ifcfg-rh/writer.c +@@ -32,6 +32,7 @@ + #include + #include + ++#include "nm-manager.h" + #include "nm-setting-connection.h" + #include "nm-setting-wired.h" + #include "nm-setting-wireless.h" +@@ -1804,13 +1805,13 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) + { + guint32 n, i; + GString *str; +- const char *master, *type; ++ const char *master, *master_iface = NULL, *type; + char *tmp; + gint i_int; +- const char *v_master = NULL; ++ const char *v_master = NULL, *v_master_uuid = NULL; ++ const char *v_bridge = NULL, *v_bridge_uuid = NULL; ++ const char *v_team_master = NULL, *v_team_master_uuid = NULL; + const char *v_slave = NULL; +- const char *v_bridge = NULL; +- const char *v_team_master = NULL; + + svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE); + svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE); +@@ -1878,25 +1879,43 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) + + master = nm_setting_connection_get_master (s_con); + if (master) { ++ /* The reader prefers the *_UUID variants, however we still try to resolve ++ * it into an interface name, so that legacy tooling is not confused. */ ++ if (!nm_utils_get_testing ()) { ++ /* This is conditional for easier testing. */ ++ master_iface = nm_manager_iface_for_uuid (nm_manager_get (), master); ++ } ++ if (!master_iface) { ++ master_iface = master; ++ master = NULL; ++ ++ } ++ + if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BOND_SETTING_NAME)) { +- v_master = master; ++ v_master_uuid = master; ++ v_master = master_iface; + v_slave = "yes"; +- } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME)) +- v_bridge = master; +- else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) { +- v_team_master = master; ++ } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME)) { ++ v_bridge_uuid = master; ++ v_bridge = master_iface; ++ } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) { ++ v_team_master_uuid = master; ++ v_team_master = master_iface; + svSetValue (ifcfg, "TYPE", NULL, FALSE); + } + } + ++ svSetValue (ifcfg, "MASTER_UUID", v_master_uuid, FALSE); + svSetValue (ifcfg, "MASTER", v_master, FALSE); + svSetValue (ifcfg, "SLAVE", v_slave, FALSE); ++ svSetValue (ifcfg, "BRIDGE_UUID", v_bridge_uuid, FALSE); + svSetValue (ifcfg, "BRIDGE", v_bridge, FALSE); ++ svSetValue (ifcfg, "TEAM_MASTER_UUID", v_team_master_uuid, FALSE); + svSetValue (ifcfg, "TEAM_MASTER", v_team_master, FALSE); + + if (nm_streq0 (type, NM_SETTING_TEAM_SETTING_NAME)) + svSetValue (ifcfg, "DEVICETYPE", TYPE_TEAM, FALSE); +- else if (master && nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) ++ else if (master_iface && nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) + svSetValue (ifcfg, "DEVICETYPE", TYPE_TEAM_PORT, FALSE); + else + svSetValue (ifcfg, "DEVICETYPE", NULL, FALSE); +-- +2.9.3 + +From f72c54a2cca791d166a7bc37f2c317b6dd6bc204 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 20 Feb 2017 13:32:39 +0100 +Subject: [PATCH] tui: generate names for bonds, teams and bridges + +This makes it more likely that the user will end up with a master +connection that has connection.interface-name property. This makes it +possible for ifcfg plugin to specify the master in the for of device +name (as opposed to UUID) for compatibility with the legacy network +tooling. + +This is equivalent to what nmcli does. + +https://bugzilla.redhat.com/show_bug.cgi?id=1369091 +(cherry picked from commit ff46158d9ecd153fa4b0be71f679fa61212715f2) +--- + clients/tui/nm-editor-utils.c | 40 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 39 insertions(+), 1 deletion(-) + +diff --git a/clients/tui/nm-editor-utils.c b/clients/tui/nm-editor-utils.c +index 0ec55f3..d5c2fd5 100644 +--- a/clients/tui/nm-editor-utils.c ++++ b/clients/tui/nm-editor-utils.c +@@ -308,6 +308,33 @@ get_available_connection_name (const char *format, + return cname; + } + ++static char * ++get_available_iface_name (const char *try_name, ++ NMClient *client) ++{ ++ const GPtrArray *connections; ++ NMConnection *connection; ++ char *new_name; ++ unsigned int num = 1; ++ int i = 0; ++ const char *ifname = NULL; ++ ++ connections = nm_client_get_connections (client); ++ ++ new_name = g_strdup (try_name); ++ while (i < connections->len) { ++ connection = NM_CONNECTION (connections->pdata[i]); ++ ifname = nm_connection_get_interface_name (connection); ++ if (g_strcmp0 (new_name, ifname) == 0) { ++ g_free (new_name); ++ new_name = g_strdup_printf ("%s%d", try_name, num++); ++ i = 0; ++ } else ++ i++; ++ } ++ return new_name; ++} ++ + /** + * nm_editor_utils_create_connection: + * @type: the type of the connection's primary #NMSetting +@@ -335,7 +362,7 @@ nm_editor_utils_create_connection (GType type, + NMConnection *connection; + NMSettingConnection *s_con; + NMSetting *s_hw, *s_slave; +- char *uuid, *id; ++ char *uuid, *id, *ifname; + int i; + + if (master) { +@@ -368,6 +395,15 @@ nm_editor_utils_create_connection (GType type, + s_hw = g_object_new (type, NULL); + nm_connection_add_setting (connection, s_hw); + ++ if (type == NM_TYPE_SETTING_BOND) ++ ifname = get_available_iface_name ("nm-bond", client); ++ else if (type == NM_TYPE_SETTING_TEAM) ++ ifname = get_available_iface_name ("nm-team", client); ++ else if (type == NM_TYPE_SETTING_BRIDGE) ++ ifname = get_available_iface_name ("nm-bridge", client); ++ else ++ ifname = NULL; ++ + if (slave_setting_type != G_TYPE_INVALID) { + s_slave = g_object_new (slave_setting_type, NULL); + nm_connection_add_setting (connection, s_slave); +@@ -383,10 +419,12 @@ nm_editor_utils_create_connection (GType type, + NM_SETTING_CONNECTION_AUTOCONNECT, !type_data->no_autoconnect, + NM_SETTING_CONNECTION_MASTER, master_uuid, + NM_SETTING_CONNECTION_SLAVE_TYPE, master_setting_type, ++ NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, + NULL); + + g_free (uuid); + g_free (id); ++ g_free (ifname); + + if (type_data->connection_setup_func) + type_data->connection_setup_func (connection, s_con, s_hw); +-- +2.9.3 + diff --git a/SOURCES/0025-remove-INFERRABLE-flag-from-dhcp-hostname-rh1421082.patch b/SOURCES/0025-remove-INFERRABLE-flag-from-dhcp-hostname-rh1421082.patch new file mode 100644 index 0000000..d14c148 --- /dev/null +++ b/SOURCES/0025-remove-INFERRABLE-flag-from-dhcp-hostname-rh1421082.patch @@ -0,0 +1,31 @@ +From 86490fbb1d5dce0cd1cff5479907cc7222afcf74 Mon Sep 17 00:00:00 2001 +From: Francesco Giudici +Date: Wed, 16 Nov 2016 18:13:55 +0100 +Subject: [PATCH] libnm-core: remove INFERRABLE flag from dhcp-hostname + property + +When assuming a dhcp connection don't consider the DHCP "Host Name" +Option (12) passed in the DHCP request for the match of the available +connections. + +https://bugzilla.redhat.com/show_bug.cgi?id=1393997 +(cherry picked from commit 0ce7da1e22abf7a4415ef40fca9f1755b8ddfa30) +--- + libnm-core/nm-setting-ip-config.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c +index 55ad7bb..39a4c63 100644 +--- a/libnm-core/nm-setting-ip-config.c ++++ b/libnm-core/nm-setting-ip-config.c +@@ -2879,7 +2879,6 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class) + g_param_spec_string (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, "", "", + NULL, + G_PARAM_READWRITE | +- NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** +-- +2.9.3 + diff --git a/SOURCES/0026-core-honor-ip-order-rh1394500.patch b/SOURCES/0026-core-honor-ip-order-rh1394500.patch new file mode 100644 index 0000000..6b16927 --- /dev/null +++ b/SOURCES/0026-core-honor-ip-order-rh1394500.patch @@ -0,0 +1,1534 @@ +From 93806baf641da6afcdfe2042c4621740352e28a2 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Fri, 14 Oct 2016 06:08:41 +0200 +Subject: [PATCH 01/10] ip-config: cleanup integer types for + nm_ip4_config_get_num_*() + +(cherry picked from commit 510626bf74c521de3dc76b9502a137f40e6bbb4f) +(cherry picked from commit 8bcf1a6e3d343f10280848f130692913f04ff195) +--- + src/nm-ip4-config.c | 32 ++++++++++++++++---------------- + src/nm-ip4-config.h | 34 +++++++++++----------------------- + src/nm-ip6-config.c | 24 ++++++++++++------------ + src/nm-ip6-config.h | 26 +++++++++----------------- + 4 files changed, 48 insertions(+), 68 deletions(-) + +diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c +index a4d4361..816c606 100644 +--- a/src/nm-ip4-config.c ++++ b/src/nm-ip4-config.c +@@ -347,7 +347,6 @@ gboolean + nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_full_sync, gint64 default_route_metric) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +- int i; + gs_unref_ptrarray GPtrArray *added_addresses = NULL; + + g_return_val_if_fail (ifindex > 0, FALSE); +@@ -359,7 +358,8 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu + + /* Routes */ + { +- int count = nm_ip4_config_get_num_routes (config); ++ guint i; ++ guint count = nm_ip4_config_get_num_routes (config); + GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), count); + gboolean success; + gs_unref_array GArray *device_route_purge_list = NULL; +@@ -1366,7 +1366,7 @@ gboolean + nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network, guint8 plen) + { + guint naddresses = nm_ip4_config_get_num_addresses (config); +- int i; ++ guint i; + in_addr_t peer_network; + + for (i = 0; i < naddresses; i++) { +@@ -1725,7 +1725,7 @@ nm_ip4_config_del_nameserver (NMIP4Config *config, guint i) + _notify (config, PROP_NAMESERVERS); + } + +-guint32 ++guint + nm_ip4_config_get_num_nameservers (const NMIP4Config *config) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +@@ -1782,7 +1782,7 @@ nm_ip4_config_del_domain (NMIP4Config *config, guint i) + _notify (config, PROP_DOMAINS); + } + +-guint32 ++guint + nm_ip4_config_get_num_domains (const NMIP4Config *config) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +@@ -1854,7 +1854,7 @@ nm_ip4_config_del_search (NMIP4Config *config, guint i) + _notify (config, PROP_SEARCHES); + } + +-guint32 ++guint + nm_ip4_config_get_num_searches (const NMIP4Config *config) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +@@ -1911,7 +1911,7 @@ nm_ip4_config_del_dns_option(NMIP4Config *config, guint i) + _notify (config, PROP_DNS_OPTIONS); + } + +-guint32 ++guint + nm_ip4_config_get_num_dns_options (const NMIP4Config *config) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +@@ -1999,7 +1999,7 @@ nm_ip4_config_del_nis_server (NMIP4Config *config, guint i) + g_array_remove_index (priv->nis, i); + } + +-guint32 ++guint + nm_ip4_config_get_num_nis_servers (const NMIP4Config *config) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +@@ -2072,7 +2072,7 @@ nm_ip4_config_del_wins (NMIP4Config *config, guint i) + _notify (config, PROP_WINS_SERVERS); + } + +-guint32 ++guint + nm_ip4_config_get_num_wins (const NMIP4Config *config) + { + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); +@@ -2147,7 +2147,7 @@ hash_u32 (GChecksum *sum, guint32 n) + void + nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only) + { +- guint32 i; ++ guint i; + const char *s; + + g_return_if_fail (config); +@@ -2294,8 +2294,8 @@ get_property (GObject *object, guint prop_id, + case PROP_ADDRESS_DATA: + { + GVariantBuilder array_builder, addr_builder; +- int naddr = nm_ip4_config_get_num_addresses (config); +- int i; ++ guint naddr = nm_ip4_config_get_num_addresses (config); ++ guint i; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < naddr; i++) { +@@ -2329,8 +2329,8 @@ get_property (GObject *object, guint prop_id, + case PROP_ADDRESSES: + { + GVariantBuilder array_builder; +- int naddr = nm_ip4_config_get_num_addresses (config); +- int i; ++ guint naddr = nm_ip4_config_get_num_addresses (config); ++ guint i; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); + for (i = 0; i < naddr; i++) { +@@ -2353,7 +2353,7 @@ get_property (GObject *object, guint prop_id, + { + GVariantBuilder array_builder, route_builder; + guint nroutes = nm_ip4_config_get_num_routes (config); +- int i; ++ guint i; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < nroutes; i++) { +@@ -2385,7 +2385,7 @@ get_property (GObject *object, guint prop_id, + { + GVariantBuilder array_builder; + guint nroutes = nm_ip4_config_get_num_routes (config); +- int i; ++ guint i; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); + for (i = 0; i < nroutes; i++) { +diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h +index f302630..71920c9 100644 +--- a/src/nm-ip4-config.h ++++ b/src/nm-ip4-config.h +@@ -58,13 +58,13 @@ NMIP4Config * nm_ip4_config_new (int ifindex); + + int nm_ip4_config_get_ifindex (const NMIP4Config *config); + +-/* Integration with nm-platform and nm-setting */ ++ + NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf); + gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_full_sync, gint64 default_route_metric); + void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric); + NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config); + +-/* Utility functions */ ++ + void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFlags merge_flags); + void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src); + void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src); +@@ -72,7 +72,7 @@ gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboole + gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 dest, guint8 plen); + void nm_ip4_config_dump (const NMIP4Config *config, const char *detail); + +-/* Gateways */ ++ + void nm_ip4_config_set_never_default (NMIP4Config *config, gboolean never_default); + gboolean nm_ip4_config_get_never_default (const NMIP4Config *config); + void nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway); +@@ -81,7 +81,6 @@ gboolean nm_ip4_config_has_gateway (const NMIP4Config *config); + guint32 nm_ip4_config_get_gateway (const NMIP4Config *config); + gint64 nm_ip4_config_get_route_metric (const NMIP4Config *config); + +-/* Addresses */ + void nm_ip4_config_reset_addresses (NMIP4Config *config); + void nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *address); + void nm_ip4_config_del_address (NMIP4Config *config, guint i); +@@ -90,73 +89,62 @@ const NMPlatformIP4Address *nm_ip4_config_get_address (const NMIP4Config *config + gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *address); + gboolean nm_ip4_config_addresses_sort (NMIP4Config *config); + +-/* Routes */ + void nm_ip4_config_reset_routes (NMIP4Config *config); + void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *route); + void nm_ip4_config_del_route (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_routes (const NMIP4Config *config); +-const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint32 i); ++guint nm_ip4_config_get_num_routes (const NMIP4Config *config); ++const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint i); + + const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host); + +-/* Nameservers */ + void nm_ip4_config_reset_nameservers (NMIP4Config *config); + void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver); + void nm_ip4_config_del_nameserver (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_nameservers (const NMIP4Config *config); ++guint nm_ip4_config_get_num_nameservers (const NMIP4Config *config); + guint32 nm_ip4_config_get_nameserver (const NMIP4Config *config, guint i); + +-/* Domains */ + void nm_ip4_config_reset_domains (NMIP4Config *config); + void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain); + void nm_ip4_config_del_domain (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_domains (const NMIP4Config *config); ++guint nm_ip4_config_get_num_domains (const NMIP4Config *config); + const char * nm_ip4_config_get_domain (const NMIP4Config *config, guint i); + +-/* Search lists */ + void nm_ip4_config_reset_searches (NMIP4Config *config); + void nm_ip4_config_add_search (NMIP4Config *config, const char *search); + void nm_ip4_config_del_search (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_searches (const NMIP4Config *config); ++guint nm_ip4_config_get_num_searches (const NMIP4Config *config); + const char * nm_ip4_config_get_search (const NMIP4Config *config, guint i); + +-/* DNS options */ + void nm_ip4_config_reset_dns_options (NMIP4Config *config); + void nm_ip4_config_add_dns_option (NMIP4Config *config, const char *option); + void nm_ip4_config_del_dns_option (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_dns_options (const NMIP4Config *config); ++guint nm_ip4_config_get_num_dns_options (const NMIP4Config *config); + const char * nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i); + +-/* DNS priority */ + void nm_ip4_config_set_dns_priority (NMIP4Config *config, gint priority); + gint nm_ip4_config_get_dns_priority (const NMIP4Config *config); + +-/* MSS */ + void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss); + guint32 nm_ip4_config_get_mss (const NMIP4Config *config); + +-/* NIS */ + void nm_ip4_config_reset_nis_servers (NMIP4Config *config); + void nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis); + void nm_ip4_config_del_nis_server (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_nis_servers (const NMIP4Config *config); ++guint nm_ip4_config_get_num_nis_servers (const NMIP4Config *config); + guint32 nm_ip4_config_get_nis_server (const NMIP4Config *config, guint i); + void nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain); + const char * nm_ip4_config_get_nis_domain (const NMIP4Config *config); + +-/* WINS */ + void nm_ip4_config_reset_wins (NMIP4Config *config); + void nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins); + void nm_ip4_config_del_wins (NMIP4Config *config, guint i); +-guint32 nm_ip4_config_get_num_wins (const NMIP4Config *config); ++guint nm_ip4_config_get_num_wins (const NMIP4Config *config); + guint32 nm_ip4_config_get_wins (const NMIP4Config *config, guint i); + +-/* MTU */ + void nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu, NMIPConfigSource source); + guint32 nm_ip4_config_get_mtu (const NMIP4Config *config); + NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *config); + +-/* Metered */ + void nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered); + gboolean nm_ip4_config_get_metered (const NMIP4Config *config); + +diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c +index 8002d61..2030907 100644 +--- a/src/nm-ip6-config.c ++++ b/src/nm-ip6-config.c +@@ -384,7 +384,6 @@ gboolean + nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_full_sync) + { + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); +- int i; + gboolean success; + + g_return_val_if_fail (ifindex > 0, FALSE); +@@ -395,7 +394,8 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_fu + + /* Routes */ + { +- int count = nm_ip6_config_get_num_routes (config); ++ guint i; ++ guint count = nm_ip6_config_get_num_routes (config); + GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), count); + const NMPlatformIP6Route *route; + +@@ -712,8 +712,8 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl + gboolean + nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *network, guint8 plen) + { +- int num = nm_ip6_config_get_num_addresses (config); +- int i; ++ guint num = nm_ip6_config_get_num_addresses (config); ++ guint i; + + nm_assert (network); + nm_assert (plen <= 128); +@@ -1626,7 +1626,7 @@ nm_ip6_config_del_nameserver (NMIP6Config *config, guint i) + _notify (config, PROP_NAMESERVERS); + } + +-guint32 ++guint + nm_ip6_config_get_num_nameservers (const NMIP6Config *config) + { + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); +@@ -1683,7 +1683,7 @@ nm_ip6_config_del_domain (NMIP6Config *config, guint i) + _notify (config, PROP_DOMAINS); + } + +-guint32 ++guint + nm_ip6_config_get_num_domains (const NMIP6Config *config) + { + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); +@@ -1755,7 +1755,7 @@ nm_ip6_config_del_search (NMIP6Config *config, guint i) + _notify (config, PROP_SEARCHES); + } + +-guint32 ++guint + nm_ip6_config_get_num_searches (const NMIP6Config *config) + { + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); +@@ -1812,7 +1812,7 @@ nm_ip6_config_del_dns_option (NMIP6Config *config, guint i) + _notify (config, PROP_DNS_OPTIONS); + } + +-guint32 ++guint + nm_ip6_config_get_num_dns_options (const NMIP6Config *config) + { + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); +@@ -2038,8 +2038,8 @@ get_property (GObject *object, guint prop_id, + case PROP_ADDRESS_DATA: + { + GVariantBuilder array_builder, addr_builder; +- int naddr = nm_ip6_config_get_num_addresses (config); +- int i; ++ guint naddr = nm_ip6_config_get_num_addresses (config); ++ guint i; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < naddr; i++) { +@@ -2069,8 +2069,8 @@ get_property (GObject *object, guint prop_id, + { + GVariantBuilder array_builder; + const struct in6_addr *gateway = nm_ip6_config_get_gateway (config); +- int naddr = nm_ip6_config_get_num_addresses (config); +- int i; ++ guint naddr = nm_ip6_config_get_num_addresses (config); ++ guint i; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuay)")); + for (i = 0; i < naddr; i++) { +diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h +index c3f8d9f..184d3e3 100644 +--- a/src/nm-ip6-config.h ++++ b/src/nm-ip6-config.h +@@ -60,13 +60,13 @@ NMIP6Config * nm_ip6_config_new_cloned (const NMIP6Config *src); + + int nm_ip6_config_get_ifindex (const NMIP6Config *config); + +-/* Integration with nm-platform and nm-setting */ ++ + NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); + gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_full_sync); + void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric); + NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config); + +-/* Utility functions */ ++ + void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFlags merge_flags); + void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src); + void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src); +@@ -74,14 +74,13 @@ gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboole + int nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *dest, guint8 plen); + void nm_ip6_config_dump (const NMIP6Config *config, const char *detail); + +-/* Gateways */ ++ + void nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default); + gboolean nm_ip6_config_get_never_default (const NMIP6Config *config); + void nm_ip6_config_set_gateway (NMIP6Config *config, const struct in6_addr *); + const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *config); + gint64 nm_ip6_config_get_route_metric (const NMIP6Config *config); + +-/* Addresses */ + void nm_ip6_config_reset_addresses (NMIP6Config *config); + void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *address); + void nm_ip6_config_del_address (NMIP6Config *config, guint i); +@@ -93,49 +92,42 @@ gboolean nm_ip6_config_addresses_sort (NMIP6Config *config, NMSettingIP6ConfigPr + gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, + const NMIP6Config *candidates); + +-/* Routes */ + void nm_ip6_config_reset_routes (NMIP6Config *config); + void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route); + void nm_ip6_config_del_route (NMIP6Config *config, guint i); +-guint32 nm_ip6_config_get_num_routes (const NMIP6Config *config); +-const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint32 i); ++guint nm_ip6_config_get_num_routes (const NMIP6Config *config); ++const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint i); + + const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host); + const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_addr *host); + +-/* Nameservers */ + void nm_ip6_config_reset_nameservers (NMIP6Config *config); + void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver); + void nm_ip6_config_del_nameserver (NMIP6Config *config, guint i); +-guint32 nm_ip6_config_get_num_nameservers (const NMIP6Config *config); ++guint nm_ip6_config_get_num_nameservers (const NMIP6Config *config); + const struct in6_addr *nm_ip6_config_get_nameserver (const NMIP6Config *config, guint i); + +-/* Domains */ + void nm_ip6_config_reset_domains (NMIP6Config *config); + void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain); + void nm_ip6_config_del_domain (NMIP6Config *config, guint i); +-guint32 nm_ip6_config_get_num_domains (const NMIP6Config *config); ++guint nm_ip6_config_get_num_domains (const NMIP6Config *config); + const char * nm_ip6_config_get_domain (const NMIP6Config *config, guint i); + +-/* Search lists */ + void nm_ip6_config_reset_searches (NMIP6Config *config); + void nm_ip6_config_add_search (NMIP6Config *config, const char *search); + void nm_ip6_config_del_search (NMIP6Config *config, guint i); +-guint32 nm_ip6_config_get_num_searches (const NMIP6Config *config); ++guint nm_ip6_config_get_num_searches (const NMIP6Config *config); + const char * nm_ip6_config_get_search (const NMIP6Config *config, guint i); + +-/* DNS options */ + void nm_ip6_config_reset_dns_options (NMIP6Config *config); + void nm_ip6_config_add_dns_option (NMIP6Config *config, const char *option); + void nm_ip6_config_del_dns_option (NMIP6Config *config, guint i); +-guint32 nm_ip6_config_get_num_dns_options (const NMIP6Config *config); ++guint nm_ip6_config_get_num_dns_options (const NMIP6Config *config); + const char * nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i); + +-/* DNS priority */ + void nm_ip6_config_set_dns_priority (NMIP6Config *config, gint priority); + gint nm_ip6_config_get_dns_priority (const NMIP6Config *config); + +-/* MSS */ + void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss); + guint32 nm_ip6_config_get_mss (const NMIP6Config *config); + +-- +2.7.4 + +From 6a079d44e4e1179a2288f85e806565e704756e2e Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 18 Nov 2016 11:48:12 +0100 +Subject: [PATCH 02/10] ip4-config: don't change order of addresses in the same + subnet + +When multiple address are assigned to an interface and the kernel must +decide which one should be used to communicate with a given IP, it +chooses the most specific one in the same subnet as the +destination. In case there are multiple addresses in the same subnet, +the primary address is choosen, which is basically the first one that +was added. + +With commit 719742513705 ("device: expose NMIP4Config:addresses in +stable/defined sort order") we sorted all the addresses before +committing the configuration, with the side effect that the order no +longer respected the one in the user configuration. + +Instead, change the sort function to keep the subnet order unchanged. + +(cherry picked from commit e02752c2ed6a8dde884021817a5da8fc101330db) +(cherry picked from commit 56cebecd414fac495617852a995a170613d98313) +--- + src/nm-ip4-config.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c +index 816c606..6941285 100644 +--- a/src/nm-ip4-config.c ++++ b/src/nm-ip4-config.c +@@ -207,8 +207,9 @@ _addresses_sort_cmp_get_prio (in_addr_t addr) + static gint + _addresses_sort_cmp (gconstpointer a, gconstpointer b) + { +- gint p1, p2, c; ++ gint p1, p2; + const NMPlatformIP4Address *a1 = a, *a2 = b; ++ guint32 n1, n2; + + /* Sort by address type. For example link local will + * be sorted *after* a global address. */ +@@ -224,9 +225,15 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b) + if ((a1->label[0] == '\0') != (a2->label[0] == '\0')) + return (a1->label[0] == '\0') ? -1 : 1; + +- /* finally sort addresses lexically */ +- c = memcmp (&a1->address, &a2->address, sizeof (a2->address)); +- return c != 0 ? c : memcmp (a1, a2, sizeof (*a1)); ++ /* Finally, sort addresses lexically. We compare only the ++ * network part so that the order of addresses in the same ++ * subnet (and thus also the primary/secondary role) is ++ * preserved. ++ */ ++ n1 = a1->address & nm_utils_ip4_prefix_to_netmask (a1->plen); ++ n2 = a2->address & nm_utils_ip4_prefix_to_netmask (a2->plen); ++ ++ return memcmp (&n1, &n2, sizeof (guint32)); + } + + gboolean +-- +2.7.4 + +From 45791b1c25a482a47a1b9c7cab5bc0f2c65f3ca7 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 18 Nov 2016 11:52:38 +0100 +Subject: [PATCH 03/10] ip4-config: cache addresses variants + +(cherry picked from commit 5ce81e23b7508c79b036ddbf4dc3dfdd2e6faec4) +(cherry picked from commit 996f325f67da91a70f7767e248b6bcf508e63a23) +--- + src/nm-ip4-config.c | 55 +++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 37 insertions(+), 18 deletions(-) + +diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c +index 6941285..315dddb 100644 +--- a/src/nm-ip4-config.c ++++ b/src/nm-ip4-config.c +@@ -55,6 +55,8 @@ typedef struct { + gint64 route_metric; + gboolean metered; + gint dns_priority; ++ GVariant *address_data_variant; ++ GVariant *addresses_variant; + } NMIP4ConfigPrivate; + + struct _NMIP4Config { +@@ -268,6 +270,17 @@ nm_ip4_config_addresses_sort (NMIP4Config *self) + + /*****************************************************************************/ + ++static void ++notify_addresses (NMIP4Config *self) ++{ ++ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); ++ ++ nm_clear_g_variant (&priv->address_data_variant); ++ nm_clear_g_variant (&priv->addresses_variant); ++ _notify (self, PROP_ADDRESS_DATA); ++ _notify (self, PROP_ADDRESSES); ++} ++ + NMIP4Config * + nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) + { +@@ -1480,8 +1493,7 @@ nm_ip4_config_reset_addresses (NMIP4Config *config) + + if (priv->addresses->len != 0) { + g_array_set_size (priv->addresses, 0); +- _notify (config, PROP_ADDRESS_DATA); +- _notify (config, PROP_ADDRESSES); ++ notify_addresses (config); + } + } + +@@ -1538,8 +1550,7 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) + + g_array_append_val (priv->addresses, *new); + NOTIFY: +- _notify (config, PROP_ADDRESS_DATA); +- _notify (config, PROP_ADDRESSES); ++ notify_addresses (config); + } + + void +@@ -1550,8 +1561,8 @@ nm_ip4_config_del_address (NMIP4Config *config, guint i) + g_return_if_fail (i < priv->addresses->len); + + g_array_remove_index (priv->addresses, i); +- _notify (config, PROP_ADDRESS_DATA); +- _notify (config, PROP_ADDRESSES); ++ ++ notify_addresses (config); + } + + guint +@@ -2274,6 +2285,8 @@ finalize (GObject *object) + NMIP4Config *self = NM_IP4_CONFIG (object); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + ++ nm_clear_g_variant (&priv->address_data_variant); ++ nm_clear_g_variant (&priv->addresses_variant); + g_array_unref (priv->addresses); + g_array_unref (priv->routes); + g_array_unref (priv->nameservers); +@@ -2299,11 +2312,19 @@ get_property (GObject *object, guint prop_id, + g_value_set_int (value, priv->ifindex); + break; + case PROP_ADDRESS_DATA: ++ case PROP_ADDRESSES: + { + GVariantBuilder array_builder, addr_builder; +- guint naddr = nm_ip4_config_get_num_addresses (config); +- guint i; ++ guint naddr, i; + ++ g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant); ++ ++ if (priv->address_data_variant) ++ goto return_cached; ++ ++ naddr = nm_ip4_config_get_num_addresses (config); ++ ++ /* Build address data variant */ + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < naddr; i++) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); +@@ -2329,16 +2350,9 @@ get_property (GObject *object, guint prop_id, + + g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); + } ++ priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); + +- g_value_take_variant (value, g_variant_builder_end (&array_builder)); +- } +- break; +- case PROP_ADDRESSES: +- { +- GVariantBuilder array_builder; +- guint naddr = nm_ip4_config_get_num_addresses (config); +- guint i; +- ++ /* Build addresses variant */ + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); + for (i = 0; i < naddr; i++) { + const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); +@@ -2352,8 +2366,13 @@ get_property (GObject *object, guint prop_id, + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + dbus_addr, 3, sizeof (guint32))); + } ++ priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); + +- g_value_take_variant (value, g_variant_builder_end (&array_builder)); ++return_cached: ++ g_value_set_variant (value, ++ prop_id == PROP_ADDRESS_DATA ? ++ priv->address_data_variant : ++ priv->addresses_variant); + } + break; + case PROP_ROUTE_DATA: +-- +2.7.4 + +From 1734568705e03430836f20529c9264a2dd9f9055 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 18 Nov 2016 11:52:45 +0100 +Subject: [PATCH 04/10] ip4-config: sort addresses only when reading the + property value + +Don't change the address order from configuration, but instead sort +addresses just before returning them to clients. + +(cherry picked from commit 9609d4da1db564ffa2379790d26b74fd7f99fc27) +(cherry picked from commit 6fdea664a467b9cf912ac8c724b9a0086c76ce6d) +--- + src/devices/nm-device.c | 2 -- + src/nm-ip4-config.c | 38 ++++++-------------------------------- + src/nm-ip4-config.h | 1 - + 3 files changed, 6 insertions(+), 35 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 380e663..0904420 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -4813,8 +4813,6 @@ END_ADD_DEFAULT_ROUTE: + priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); + } + +- nm_ip4_config_addresses_sort (composite); +- + /* Allow setting MTU etc */ + if (commit) { + if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) +diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c +index 315dddb..7b42235 100644 +--- a/src/nm-ip4-config.c ++++ b/src/nm-ip4-config.c +@@ -238,36 +238,6 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b) + return memcmp (&n1, &n2, sizeof (guint32)); + } + +-gboolean +-nm_ip4_config_addresses_sort (NMIP4Config *self) +-{ +- NMIP4ConfigPrivate *priv; +- size_t data_len = 0; +- char *data_pre = NULL; +- gboolean changed; +- +- g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE); +- +- priv = NM_IP4_CONFIG_GET_PRIVATE (self); +- if (priv->addresses->len > 1) { +- data_len = priv->addresses->len * g_array_get_element_size (priv->addresses); +- data_pre = g_new (char, data_len); +- memcpy (data_pre, priv->addresses->data, data_len); +- +- g_array_sort (priv->addresses, _addresses_sort_cmp); +- +- changed = memcmp (data_pre, priv->addresses->data, data_len) != 0; +- g_free (data_pre); +- +- if (changed) { +- _notify (self, PROP_ADDRESS_DATA); +- _notify (self, PROP_ADDRESSES); +- return TRUE; +- } +- } +- return FALSE; +-} +- + /*****************************************************************************/ + + static void +@@ -2315,6 +2285,7 @@ get_property (GObject *object, guint prop_id, + case PROP_ADDRESSES: + { + GVariantBuilder array_builder, addr_builder; ++ gs_unref_array GArray *new = NULL; + guint naddr, i; + + g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant); +@@ -2323,11 +2294,14 @@ get_property (GObject *object, guint prop_id, + goto return_cached; + + naddr = nm_ip4_config_get_num_addresses (config); ++ new = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Address), naddr); ++ g_array_append_vals (new, priv->addresses->data, priv->addresses->len); ++ g_array_sort (new, _addresses_sort_cmp); + + /* Build address data variant */ + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < naddr; i++) { +- const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); ++ const NMPlatformIP4Address *address = &g_array_index (new, NMPlatformIP4Address, i); + + g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&addr_builder, "{sv}", +@@ -2355,7 +2329,7 @@ get_property (GObject *object, guint prop_id, + /* Build addresses variant */ + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); + for (i = 0; i < naddr; i++) { +- const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); ++ const NMPlatformIP4Address *address = &g_array_index (new, NMPlatformIP4Address, i); + guint32 dbus_addr[3]; + + dbus_addr[0] = address->address; +diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h +index 71920c9..6fc45dc 100644 +--- a/src/nm-ip4-config.h ++++ b/src/nm-ip4-config.h +@@ -87,7 +87,6 @@ void nm_ip4_config_del_address (NMIP4Config *config, guint i); + guint nm_ip4_config_get_num_addresses (const NMIP4Config *config); + const NMPlatformIP4Address *nm_ip4_config_get_address (const NMIP4Config *config, guint i); + gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *address); +-gboolean nm_ip4_config_addresses_sort (NMIP4Config *config); + + void nm_ip4_config_reset_routes (NMIP4Config *config); + void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *route); +-- +2.7.4 + +From cfe4639961a0e19ae5aa4457566199680dfca8e4 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 18 Nov 2016 11:52:50 +0100 +Subject: [PATCH 05/10] ip6-config: cache addresses variants + +(cherry picked from commit ed4d5889c7d5d2dc18353adc3a1dfeaa538c8f2e) +(cherry picked from commit 6633eaf75c1d8f1e1f42717ba9d4e95530569653) +--- + src/nm-ip6-config.c | 59 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 38 insertions(+), 21 deletions(-) + +diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c +index 2030907..b80c958 100644 +--- a/src/nm-ip6-config.c ++++ b/src/nm-ip6-config.c +@@ -48,6 +48,8 @@ typedef struct { + int ifindex; + gint64 route_metric; + gint dns_priority; ++ GVariant *address_data_variant; ++ GVariant *addresses_variant; + } NMIP6ConfigPrivate; + + struct _NMIP6Config { +@@ -106,6 +108,17 @@ nm_ip6_config_get_ifindex (const NMIP6Config *config) + + /******************************************************************/ + ++static void ++notify_addresses (NMIP6Config *self) ++{ ++ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); ++ ++ nm_clear_g_variant (&priv->address_data_variant); ++ nm_clear_g_variant (&priv->addresses_variant); ++ _notify (self, PROP_ADDRESS_DATA); ++ _notify (self, PROP_ADDRESSES); ++} ++ + /** + * nm_ip6_config_capture_resolv_conf(): + * @nameservers: array of struct in6_addr +@@ -287,8 +300,7 @@ nm_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_t + g_free (data_pre); + + if (changed) { +- _notify (self, PROP_ADDRESS_DATA); +- _notify (self, PROP_ADDRESSES); ++ notify_addresses (self); + return TRUE; + } + } +@@ -1282,8 +1294,7 @@ nm_ip6_config_reset_addresses (NMIP6Config *config) + + if (priv->addresses->len != 0) { + g_array_set_size (priv->addresses, 0); +- _notify (config, PROP_ADDRESS_DATA); +- _notify (config, PROP_ADDRESSES); ++ notify_addresses (config); + } + } + +@@ -1340,8 +1351,7 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) + + g_array_append_val (priv->addresses, *new); + NOTIFY: +- _notify (config, PROP_ADDRESS_DATA); +- _notify (config, PROP_ADDRESSES); ++notify_addresses (config); + } + + void +@@ -1352,8 +1362,8 @@ nm_ip6_config_del_address (NMIP6Config *config, guint i) + g_return_if_fail (i < priv->addresses->len); + + g_array_remove_index (priv->addresses, i); +- _notify (config, PROP_ADDRESS_DATA); +- _notify (config, PROP_ADDRESSES); ++ ++ notify_addresses (config); + } + + guint +@@ -2000,6 +2010,8 @@ finalize (GObject *object) + g_ptr_array_unref (priv->domains); + g_ptr_array_unref (priv->searches); + g_ptr_array_unref (priv->dns_options); ++ nm_clear_g_variant (&priv->address_data_variant); ++ nm_clear_g_variant (&priv->addresses_variant); + + G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object); + } +@@ -2036,10 +2048,19 @@ get_property (GObject *object, guint prop_id, + g_value_set_int (value, priv->ifindex); + break; + case PROP_ADDRESS_DATA: ++ case PROP_ADDRESSES: + { + GVariantBuilder array_builder, addr_builder; +- guint naddr = nm_ip6_config_get_num_addresses (config); +- guint i; ++ const struct in6_addr *gateway; ++ guint naddr, i; ++ ++ g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant); ++ ++ if (priv->address_data_variant) ++ goto return_cached; ++ ++ naddr = nm_ip6_config_get_num_addresses (config); ++ gateway = nm_ip6_config_get_gateway (config); + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < naddr; i++) { +@@ -2061,16 +2082,7 @@ get_property (GObject *object, guint prop_id, + + g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); + } +- +- g_value_take_variant (value, g_variant_builder_end (&array_builder)); +- } +- break; +- case PROP_ADDRESSES: +- { +- GVariantBuilder array_builder; +- const struct in6_addr *gateway = nm_ip6_config_get_gateway (config); +- guint naddr = nm_ip6_config_get_num_addresses (config); +- guint i; ++ priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuay)")); + for (i = 0; i < naddr; i++) { +@@ -2085,7 +2097,12 @@ get_property (GObject *object, guint prop_id, + 16, 1)); + } + +- g_value_take_variant (value, g_variant_builder_end (&array_builder)); ++ priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); ++return_cached: ++ g_value_set_variant (value, ++ prop_id == PROP_ADDRESS_DATA ? ++ priv->address_data_variant : ++ priv->addresses_variant); + } + break; + case PROP_ROUTE_DATA: +-- +2.7.4 + +From 4109620858ea6156a952353a4a6a7ff361d30c7a Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 18 Nov 2016 11:52:53 +0100 +Subject: [PATCH 06/10] ip6-config: add nm_ip6_config_set_privacy() + +(cherry picked from commit 803a79f778ddc50d9ec387ab6a01cc5f5418e20f) +(cherry picked from commit 450572cff48f0dde662cccd8d816472629ef824e) +--- + src/devices/nm-device.c | 9 +++++---- + src/nm-ip6-config.c | 21 ++++++++++++++++++--- + src/nm-ip6-config.h | 5 +++-- + src/tests/test-ip6-config.c | 9 ++++++--- + 4 files changed, 32 insertions(+), 12 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index 0904420..cf506a4 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -5432,13 +5432,15 @@ ip6_config_merge_and_apply (NMDevice *self, + + /* If no config was passed in, create a new one */ + composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); ++ nm_ip6_config_set_privacy (composite, ++ priv->rdisc ? ++ priv->rdisc_use_tempaddr : ++ NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + init_ip6_config_dns_priority (self, composite); + + if (commit) + ensure_con_ip6_config (self); + +- g_assert (composite); +- + /* Merge all the IP configs into the composite config */ + if (priv->ac_ip6_config) { + nm_ip6_config_merge (composite, priv->ac_ip6_config, +@@ -5565,8 +5567,7 @@ END_ADD_DEFAULT_ROUTE: + priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6); + } + +- nm_ip6_config_addresses_sort (composite, +- priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); ++ nm_ip6_config_addresses_sort (composite); + + /* Allow setting MTU etc */ + if (commit) { +diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c +index b80c958..893302b 100644 +--- a/src/nm-ip6-config.c ++++ b/src/nm-ip6-config.c +@@ -50,6 +50,7 @@ typedef struct { + gint dns_priority; + GVariant *address_data_variant; + GVariant *addresses_variant; ++ NMSettingIP6ConfigPrivacy privacy; + } NMIP6ConfigPrivate; + + struct _NMIP6Config { +@@ -106,7 +107,15 @@ nm_ip6_config_get_ifindex (const NMIP6Config *config) + return NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex; + } + +-/******************************************************************/ ++void ++nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy) ++{ ++ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); ++ ++ priv->privacy = privacy; ++} ++ ++/*****************************************************************************/ + + static void + notify_addresses (NMIP6Config *self) +@@ -279,7 +288,7 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) + } + + gboolean +-nm_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_temporary) ++nm_ip6_config_addresses_sort (NMIP6Config *self) + { + NMIP6ConfigPrivate *priv; + size_t data_len = 0; +@@ -294,7 +303,8 @@ nm_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_t + data_pre = g_new (char, data_len); + memcpy (data_pre, priv->addresses->data, data_len); + +- g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary)); ++ g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, ++ GINT_TO_POINTER (priv->privacy)); + + changed = memcmp (data_pre, priv->addresses->data, data_len) != 0; + g_free (data_pre); +@@ -1168,6 +1178,11 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev + has_minor_changes = TRUE; + } + ++ if (src_priv->privacy != dst_priv->privacy) { ++ nm_ip6_config_set_privacy (dst, src_priv->privacy); ++ has_minor_changes = TRUE; ++ } ++ + #if NM_MORE_ASSERTS + /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes + * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ +diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h +index 184d3e3..9454c0f 100644 +--- a/src/nm-ip6-config.h ++++ b/src/nm-ip6-config.h +@@ -88,7 +88,7 @@ guint nm_ip6_config_get_num_addresses (const NMIP6Config *config); + const NMPlatformIP6Address *nm_ip6_config_get_address (const NMIP6Config *config, guint i); + const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *config, gboolean linklocal); + gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *address); +-gboolean nm_ip6_config_addresses_sort (NMIP6Config *config, NMSettingIP6ConfigPrivacy use_temporary); ++gboolean nm_ip6_config_addresses_sort (NMIP6Config *config); + gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, + const NMIP6Config *candidates); + +@@ -134,7 +134,8 @@ guint32 nm_ip6_config_get_mss (const NMIP6Config *config); + void nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only); + gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b); + +-/******************************************************/ ++void nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy); ++ + /* Testing-only functions */ + + gboolean nm_ip6_config_capture_resolv_conf (GArray *nameservers, +diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c +index 3eceec0..de89014 100644 +--- a/src/tests/test-ip6-config.c ++++ b/src/tests/test-ip6-config.c +@@ -238,10 +238,13 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config + { + int addr_count = nm_ip6_config_get_num_addresses (config); + int i, irepeat; +- NMIP6Config *copy = nmtst_ip6_config_clone (config); +- NMIP6Config *copy2 = nmtst_ip6_config_clone (config); ++ NMIP6Config *copy, *copy2; + int *idx = g_new (int, addr_count); + ++ nm_ip6_config_set_privacy (config, use_tempaddr); ++ copy = nmtst_ip6_config_clone (config); ++ copy2 = nmtst_ip6_config_clone (config); ++ + /* initialize the array of indeces, and keep shuffling them for every @repeat iteration. */ + for (i = 0; i < addr_count; i++) + idx[i] = i; +@@ -257,7 +260,7 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config + } + + /* reorder them again */ +- nm_ip6_config_addresses_sort (copy, use_tempaddr); ++ nm_ip6_config_addresses_sort (copy); + + /* check equality using nm_ip6_config_equal() */ + if (!nm_ip6_config_equal (copy, config)) { +-- +2.7.4 + +From 9edf0387766c4060b3e8472eb1eb44e66fd968de Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Fri, 18 Nov 2016 11:52:56 +0100 +Subject: [PATCH 07/10] ip6-config: sort addresses only when reading the + property value + +Don't change the address order from configuration, but instead sort +addresses just before returning them to clients. + +(cherry picked from commit 0a0bca9c7fad072c31c91f93a9200c83aab37d0c) +(cherry picked from commit 2ea42eee5ab11f8540dfec4140e548b9ee48af69) +--- + src/devices/nm-device.c | 2 -- + src/nm-ip6-config.c | 9 +++++++-- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c +index cf506a4..262ef86 100644 +--- a/src/devices/nm-device.c ++++ b/src/devices/nm-device.c +@@ -5567,8 +5567,6 @@ END_ADD_DEFAULT_ROUTE: + priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6); + } + +- nm_ip6_config_addresses_sort (composite); +- + /* Allow setting MTU etc */ + if (commit) { + NMUtilsIPv6IfaceId iid; +diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c +index 893302b..a021124 100644 +--- a/src/nm-ip6-config.c ++++ b/src/nm-ip6-config.c +@@ -2066,6 +2066,7 @@ get_property (GObject *object, guint prop_id, + case PROP_ADDRESSES: + { + GVariantBuilder array_builder, addr_builder; ++ gs_unref_array GArray *new = NULL; + const struct in6_addr *gateway; + guint naddr, i; + +@@ -2076,10 +2077,14 @@ get_property (GObject *object, guint prop_id, + + naddr = nm_ip6_config_get_num_addresses (config); + gateway = nm_ip6_config_get_gateway (config); ++ new = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Address), naddr); ++ g_array_append_vals (new, priv->addresses->data, naddr); ++ g_array_sort_with_data (new, _addresses_sort_cmp, ++ GINT_TO_POINTER (priv->privacy)); + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + for (i = 0; i < naddr; i++) { +- const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i); ++ const NMPlatformIP6Address *address = &g_array_index (new, NMPlatformIP6Address, i); + + g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&addr_builder, "{sv}", +@@ -2101,7 +2106,7 @@ get_property (GObject *object, guint prop_id, + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuay)")); + for (i = 0; i < naddr; i++) { +- const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i); ++ const NMPlatformIP6Address *address = &g_array_index (new, NMPlatformIP6Address, i); + + g_variant_builder_add (&array_builder, "(@ayu@ay)", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, +-- +2.7.4 + +From acddbf6f801303698a0903c835472691ecd1a837 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Mon, 9 Jan 2017 17:57:45 +0100 +Subject: [PATCH 08/10] platform: don't update IPv6 temporary addresses + +The kernel already takes care of adding and updating temporary +addresses when an address with IFA_F_MANAGETEMPADDR flag is added or +updated; doing it also in nm_platform_ip6_address_sync() can overwrite +the changes done by kernel, especially because since commit +0a0bca9c7fad ("ip6-config: sort addresses only when reading the +property value") there is no guarantee that temporary addresses are +before the public ones in the IPv6 configuration. + +Still delete temporary addresses, but don't add or update them. + +(cherry picked from commit 1dbd9d7948e61f44a56e256c4d9fe60831663861) +(cherry picked from commit a25b3327c7ffdf528da7e47a819201e216d17829) +--- + src/platform/nm-platform.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c +index 9dace69..2d69712 100644 +--- a/src/platform/nm-platform.c ++++ b/src/platform/nm-platform.c +@@ -2816,6 +2816,11 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known + const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); + guint32 lifetime, preferred; + ++ if (NM_FLAGS_HAS (known_address->n_ifa_flags, IFA_F_TEMPORARY)) { ++ /* Kernel manages these */ ++ continue; ++ } ++ + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + continue; +-- +2.7.4 + +From 47c0c4cb696dd378e4273d0ff19c8b4ef8b5cbf2 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Mon, 14 Nov 2016 20:52:24 +0100 +Subject: [PATCH 09/10] platform: fix the order of addition of primary and + secondary IPv4 addresses + +nm_platform_ip4_address_sync() tries to apply the new configuration +with the minimum effort and doesn't delete addresses if they are +already present on the interface. This can break the ordering, as an +existing address would be promoted by kernel to primary, even if it +was last in our configuration. + +Add some logic to ensure the correct order of addresses is always +enforced. This fixes situations like: + + # nmcli connection add type ethernet ifname eth0 con-name t \ + ipv4.method manual \ + ipv4.addresses "1.1.1.1/24,1.1.1.2/24,1.1.1.5/24" + # nmcli connection up t + + => addresses are applied in the right order: + inet 1.1.1.1/24 brd 1.1.1.255 scope global eth0 + inet 1.1.1.2/24 brd 1.1.1.255 scope global secondary eth0 + inet 1.1.1.5/24 brd 1.1.1.255 scope global secondary eth0 + + # nmcli connection mod t ipv4.addresses "1.1.1.5/24,1.1.1.2/24,1.1.1.1/24" + # nmcli device reapply eth0 + + => order is wrong: + inet 1.1.1.2/24 brd 1.1.1.255 scope global eth0 + inet 1.1.1.5/24 brd 1.1.1.255 scope global secondary eth0 + inet 1.1.1.1/24 brd 1.1.1.255 scope global secondary eth0 + +Co-Authored-By: Thomas Haller +(cherry picked from commit 2f68a5004153cea9878999bf3a442ecda263e5f7) +(cherry picked from commit 8b36e99ffea19416011ef8a60be8e7acf9f69467) +--- + src/platform/nm-platform.c | 161 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 151 insertions(+), 10 deletions(-) + +diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c +index 2d69712..9c8af28 100644 +--- a/src/platform/nm-platform.c ++++ b/src/platform/nm-platform.c +@@ -2663,14 +2663,14 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr + return klass->ip6_address_get (self, ifindex, address, plen); + } + +-static gboolean ++static const NMPlatformIP4Address * + array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint32 now) + { + guint len = addresses ? addresses->len : 0; + guint i; + + for (i = 0; i < len; i++) { +- NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); ++ const NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); + + if ( candidate->address == address->address + && candidate->plen == address->plen +@@ -2679,11 +2679,11 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address + + if (nm_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, &lifetime, &preferred)) +- return TRUE; ++ return candidate; + } + } + +- return FALSE; ++ return NULL; + } + + static gboolean +@@ -2707,6 +2707,97 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address + return FALSE; + } + ++static gboolean ++_ptr_inside_ip4_addr_array (const GArray *array, gconstpointer needle) ++{ ++ return needle >= (gconstpointer) &g_array_index (array, const NMPlatformIP4Address, 0) ++ && needle < (gconstpointer) &g_array_index (array, const NMPlatformIP4Address, array->len); ++} ++ ++static void ++ip4_addr_subnets_destroy_index (GHashTable *ht, const GArray *addresses) ++{ ++ GHashTableIter iter; ++ gpointer p; ++ ++ g_hash_table_iter_init (&iter, ht); ++ ++ while (g_hash_table_iter_next (&iter, NULL, &p)) { ++ if (!_ptr_inside_ip4_addr_array (addresses, p)) { ++ g_ptr_array_free ((GPtrArray *) p, TRUE); ++ } ++ } ++ ++ g_hash_table_unref (ht); ++} ++ ++static GHashTable * ++ip4_addr_subnets_build_index (const GArray *addresses, gboolean consider_flags) ++{ ++ const NMPlatformIP4Address *address; ++ gpointer p; ++ GHashTable *subnets; ++ GPtrArray *ptr; ++ guint32 net; ++ guint i; ++ gint position; ++ ++ if (!addresses) ++ return NULL; ++ ++ subnets = g_hash_table_new_full (g_direct_hash, ++ g_direct_equal, ++ NULL, ++ NULL); ++ ++ /* Build a hash table of all addresses per subnet */ ++ for (i = 0; i < addresses->len; i++) { ++ address = &g_array_index (addresses, const NMPlatformIP4Address, i); ++ net = address->address & nm_utils_ip4_prefix_to_netmask (address->plen); ++ if (!g_hash_table_lookup_extended (subnets, GUINT_TO_POINTER (net), NULL, &p)) { ++ g_hash_table_insert (subnets, GUINT_TO_POINTER (net), (gpointer) address); ++ continue; ++ } ++ if (_ptr_inside_ip4_addr_array (addresses, p)) { ++ ptr = g_ptr_array_new (); ++ g_hash_table_insert (subnets, GUINT_TO_POINTER (net), ptr); ++ g_ptr_array_add (ptr, p); ++ } else ++ ptr = p; ++ ++ if (!consider_flags || NM_FLAGS_HAS (address->n_ifa_flags, IFA_F_SECONDARY)) ++ position = -1; /* append */ ++ else ++ position = 0; /* prepend */ ++ ++ g_ptr_array_insert (ptr, position, (gpointer) address); ++ } ++ ++ return subnets; ++} ++ ++static gboolean ++ip4_addr_subnets_is_secondary (const NMPlatformIP4Address *address, GHashTable *subnets, const GArray *addresses, GPtrArray **out_addr_list) ++{ ++ GPtrArray *addr_list; ++ gpointer p; ++ guint32 net; ++ ++ net = address->address & nm_utils_ip4_prefix_to_netmask (address->plen); ++ p = g_hash_table_lookup (subnets, GUINT_TO_POINTER (net)); ++ nm_assert (p); ++ if (!_ptr_inside_ip4_addr_array (addresses, p)) { ++ addr_list = p; ++ if (addr_list->pdata[0] != address) { ++ NM_SET_OUT (out_addr_list, addr_list); ++ return TRUE; ++ } ++ } else ++ nm_assert ((gconstpointer) address == p); ++ NM_SET_OUT (out_addr_list, NULL); ++ return FALSE; ++} ++ + /** + * nm_platform_ip4_address_sync: + * @self: platform instance +@@ -2728,19 +2819,64 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known + { + GArray *addresses; + NMPlatformIP4Address *address; ++ const NMPlatformIP4Address *known_address; + gint32 now = nm_utils_get_monotonic_timestamp_s (); +- int i; ++ GHashTable *plat_subnets; ++ GHashTable *known_subnets; ++ GPtrArray *ptr; ++ int i, j; + + _CHECK_SELF (self, klass, FALSE); + +- /* Delete unknown addresses */ + addresses = nm_platform_ip4_address_get_all (self, ifindex); ++ plat_subnets = ip4_addr_subnets_build_index (addresses, TRUE); ++ known_subnets = ip4_addr_subnets_build_index (known_addresses, FALSE); ++ ++ /* Delete unknown addresses */ + for (i = 0; i < addresses->len; i++) { + address = &g_array_index (addresses, NMPlatformIP4Address, i); + +- if (!array_contains_ip4_address (known_addresses, address, now)) +- nm_platform_ip4_address_delete (self, ifindex, address->address, address->plen, address->peer_address); ++ if (!address->ifindex) { ++ /* Already deleted */ ++ continue; ++ } ++ ++ known_address = array_contains_ip4_address (known_addresses, address, now); ++ if (known_address) { ++ gboolean secondary; ++ ++ secondary = ip4_addr_subnets_is_secondary (known_address, known_subnets, known_addresses, NULL); ++ /* Ignore the matching address if it has a different primary/slave ++ * role. */ ++ if (secondary != NM_FLAGS_HAS (address->n_ifa_flags, IFA_F_SECONDARY)) ++ known_address = NULL; ++ } ++ ++ if (!known_address) { ++ nm_platform_ip4_address_delete (self, ifindex, ++ address->address, ++ address->plen, ++ address->peer_address); ++ if ( !ip4_addr_subnets_is_secondary (address, plat_subnets, addresses, &ptr) ++ && ptr) { ++ /* If we just deleted a primary addresses and there were ++ * secondary ones the kernel can do two things, depending on ++ * version and sysctl setting: delete also secondary addresses ++ * or promote a secondary to primary. Ensure that secondary ++ * addresses are deleted, so that we can start with a clean ++ * slate and add addresses in the right order. */ ++ for (j = 1; j < ptr->len; j++) { ++ address = ptr->pdata[j]; ++ nm_platform_ip4_address_delete (self, ifindex, ++ address->address, ++ address->plen, ++ address->peer_address); ++ address->ifindex = 0; ++ } ++ } ++ } + } ++ ip4_addr_subnets_destroy_index (plat_subnets, addresses); + g_array_free (addresses, TRUE); + + if (out_added_addresses) +@@ -2751,17 +2887,20 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known + + /* Add missing addresses */ + for (i = 0; i < known_addresses->len; i++) { +- const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); + guint32 lifetime, preferred; + ++ known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); ++ + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + continue; + + if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, + known_address->peer_address, lifetime, preferred, +- 0, known_address->label)) ++ 0, known_address->label)) { ++ ip4_addr_subnets_destroy_index (known_subnets, known_addresses); + return FALSE; ++ } + + if (out_added_addresses) { + if (!*out_added_addresses) +@@ -2770,6 +2909,8 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known + } + } + ++ ip4_addr_subnets_destroy_index (known_subnets, known_addresses); ++ + return TRUE; + } + +-- +2.7.4 + +From 0f74ac6831027e15ee35822c83674540c1cb82bc Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 8 Feb 2017 14:47:14 +0100 +Subject: [PATCH 10/10] platform: fix detection of primary/secondary addresses + +ip4_addr_subnets_is_secondary() should fill the list of addresses in +the same subnet also when returning FALSE, because +nm_platform_ip4_address_sync() uses it. + +Fixes: 2f68a5004153cea9878999bf3a442ecda263e5f7 +(cherry picked from commit a347962831ed127338a13b7a0939302d42bcfe60) +(cherry picked from commit 6913311d47a9045ac10f855fc3097c2304c56c43) +--- + src/platform/nm-platform.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c +index 9c8af28..8fba7ab 100644 +--- a/src/platform/nm-platform.c ++++ b/src/platform/nm-platform.c +@@ -2776,6 +2776,18 @@ ip4_addr_subnets_build_index (const GArray *addresses, gboolean consider_flags) + return subnets; + } + ++/** ++ * ip4_addr_subnets_is_secondary: ++ * @address: an address ++ * @subnets: the hash table mapping subnets to addresses ++ * @addresses: array of addresses in the hash table ++ * @out_addr_list: array of addresses belonging to the same subnet ++ * ++ * Checks whether @address is secondary and returns in @out_addr_list the list of addresses ++ * belonging to the same subnet, if it contains other elements. ++ * ++ * Returns: %TRUE if the address is secondary, %FALSE otherwise ++ */ + static gboolean + ip4_addr_subnets_is_secondary (const NMPlatformIP4Address *address, GHashTable *subnets, const GArray *addresses, GPtrArray **out_addr_list) + { +@@ -2788,13 +2800,13 @@ ip4_addr_subnets_is_secondary (const NMPlatformIP4Address *address, GHashTable * + nm_assert (p); + if (!_ptr_inside_ip4_addr_array (addresses, p)) { + addr_list = p; +- if (addr_list->pdata[0] != address) { +- NM_SET_OUT (out_addr_list, addr_list); ++ NM_SET_OUT (out_addr_list, addr_list); ++ if (addr_list->pdata[0] != address) + return TRUE; +- } +- } else ++ } else { + nm_assert ((gconstpointer) address == p); +- NM_SET_OUT (out_addr_list, NULL); ++ NM_SET_OUT (out_addr_list, NULL); ++ } + return FALSE; + } + +-- +2.7.4 + diff --git a/SPECS/NetworkManager.spec b/SPECS/NetworkManager.spec index c54302e..db1ed66 100644 --- a/SPECS/NetworkManager.spec +++ b/SPECS/NetworkManager.spec @@ -12,7 +12,7 @@ %global rpm_version 1.4.0 %global real_version 1.4.0 -%global release_version 14 +%global release_version 17 %global epoch_version 1 %global obsoletes_nmver 1:0.9.9.95-1 @@ -127,6 +127,9 @@ Patch20: 0020-fix-assume-bond-and-infiniband-rh1375558.patch Patch21: 0021-assume-devices-with-slaves-rh1333983.patch Patch22: 0022-no-unmanage-on-quit-rh1371126.patch Patch23: 0023-udev-initialized-race-rh1388286.patch +Patch24: 0024-master-name-uuid-rh1369008.patch +Patch25: 0025-remove-INFERRABLE-flag-from-dhcp-hostname-rh1421082.patch +Patch26: 0026-core-honor-ip-order-rh1394500.patch Requires(post): systemd Requires(preun): systemd @@ -398,6 +401,9 @@ by nm-connection-editor and nm-applet in a non-graphical environment. %patch21 -p1 %patch22 -p1 %patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 %build %if %{with regen_docs} @@ -703,6 +709,16 @@ fi %endif %changelog +* Mon Feb 20 2017 Lubomir Rintel - 1:1.4.0-17 +- tui: generate names for bonds, teams and bridges (rh#1369091) + +* Tue Feb 14 2017 Francesco Giudici - 1:1.4.0-16 +- libnm-core: remove INFERRABLE flag from dhcp-hostname property (rh#1421082) +- core: honor order of IP addresses from configuration (rh#1394500) + +* Mon Jan 16 2017 Lubomir Rintel - 1:1.4.0-15 +- ifcfg-rh: write the master device name even if the master property is an UUID (rh#1369091) + * Tue Dec 13 2016 Thomas Haller - 1:1.4.0-14 - core: avoid race reading permanent MAC address before udev initialized (rh#1388286)