diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 2389015528..8d930b1cbc 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -4319,6 +4319,8 @@ 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 afa5615cfe..3973011eca 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -29,6 +29,7 @@ #include "nm-utils.h" #include "nm-platform.h" +#include "nm-platform-utils.h" #include "NetworkManagerUtils.h" #include "nm-route-manager.h" #include "nm-core-internal.h" @@ -183,6 +184,73 @@ routes_are_duplicate (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, (!consider_gateway_and_metric || (a->gateway == b->gateway && a->metric == b->metric)); } +/*****************************************************************************/ + +static gint +_addresses_sort_cmp_get_prio (in_addr_t addr) +{ + if (nmp_utils_ip4_address_is_link_local (addr)) + return 0; + return 1; +} + +static gint +_addresses_sort_cmp (gconstpointer a, gconstpointer b) +{ + gint p1, p2, c; + const NMPlatformIP4Address *a1 = a, *a2 = b; + + /* Sort by address type. For example link local will + * be sorted *after* a global address. */ + p1 = _addresses_sort_cmp_get_prio (a1->address); + p2 = _addresses_sort_cmp_get_prio (a2->address); + if (p1 != p2) + return p1 > p2 ? -1 : 1; + + /* Sort the addresses based on their source. */ + if (a1->source != a2->source) + return a1->source > a2->source ? -1 : 1; + + 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)); +} + +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; +} + +/*****************************************************************************/ + NMIP4Config * nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) { diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 514ba80226..02bc8b07f1 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -98,6 +98,7 @@ 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); /* Routes */ void nm_ip4_config_reset_routes (NMIP4Config *config);