device: expose NMIP4Config:addresses in stable/defined sort order

Like we already do for IPv6 addresses, we should expose addresses
in a defined, stable sort order.

Clients usually show the addresses in the same order as obtained
via D-Bus.
This commit is contained in:
Thomas Haller
2016-02-18 20:23:10 +01:00
parent 328c733a6a
commit 7197425137
3 changed files with 71 additions and 0 deletions

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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);