diff options
author | Thomas Haller <thaller@redhat.com> | 2014-04-11 11:17:24 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-04-11 11:17:53 +0200 |
commit | e3eb7605bee05b9158da3456bc2616e9dfef6387 (patch) | |
tree | 41ff4d3e49131d477c77d8fa487bf7c8ef52e8bc | |
parent | 583eba38280628da9c645d402483f9fd0927005a (diff) | |
parent | 86f8066177ffdfd2890774f4f230919dfd322c1d (diff) | |
download | NetworkManager-e3eb7605bee05b9158da3456bc2616e9dfef6387.tar.gz |
core: merge branch 'th/bgo726525_sort_ip6_addresses'
https://bugzilla.gnome.org/show_bug.cgi?id=726525
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | libnm-util/Makefile.am | 3 | ||||
-rw-r--r-- | libnm-util/nm-test-utils.h | 261 | ||||
-rw-r--r-- | src/devices/nm-device.c | 5 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 120 | ||||
-rw-r--r-- | src/nm-ip6-config.h | 4 | ||||
-rw-r--r-- | src/tests/test-ip6-config.c | 171 |
6 files changed, 493 insertions, 71 deletions
diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index 84f4aa303d..f586f91825 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -58,7 +58,8 @@ libnm_util_la_private_headers = \ nm-param-spec-specialized.h \ nm-util-private.h \ nm-utils-private.h \ - nm-setting-private.h + nm-setting-private.h \ + nm-test-utils.h libnm_util_la_csources = \ crypto.c \ diff --git a/libnm-util/nm-test-utils.h b/libnm-util/nm-test-utils.h new file mode 100644 index 0000000000..a3de61ad64 --- /dev/null +++ b/libnm-util/nm-test-utils.h @@ -0,0 +1,261 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2014 Red Hat, Inc. + */ + +#ifndef __NM_TEST_UTILS_H__ +#define __NM_TEST_UTILS_H__ + + +#include <arpa/inet.h> +#include <glib.h> + + +struct __nmtst_internal +{ + GRand *rand0; + guint32 rand_seed; + GRand *rand; +}; + +extern struct __nmtst_internal __nmtst_internal; + +#define NMTST_DEFINE() \ + struct __nmtst_internal __nmtst_internal = { 0 }; + +inline void nmtst_init (int *argc, char ***argv); + +inline void +nmtst_init (int *argc, char ***argv) +{ + g_assert (!__nmtst_internal.rand0); + + g_assert (!((!!argc) ^ (!!argv))); + if (argc) { + /* g_test_init() is a variadic function, so we cannot pass it + * (variadic) arguments. If you need to pass additional parameters, + * call nmtst_init() with argc==NULL and call g_test_init() yourself. */ + g_test_init (argc, argv, NULL); + } + + g_type_init (); + + __nmtst_internal.rand0 = g_rand_new_with_seed (0); +} + +inline GRand *nmtst_get_rand0 (void); + +inline GRand * +nmtst_get_rand0 () +{ + g_assert (__nmtst_internal.rand0); + return __nmtst_internal.rand0; +} + +inline GRand *nmtst_get_rand (void); + +inline GRand * +nmtst_get_rand () +{ + if (G_UNLIKELY (!__nmtst_internal.rand)) { + guint32 seed; + const char *str; + + if ((str = g_getenv ("NMTST_SEED_RAND"))) { + gchar *s; + gint64 i; + + i = g_ascii_strtoll (str, &s, 0); + g_assert (s[0] == '\0' && i >= 0 && i < G_MAXINT32); + + seed = i; + __nmtst_internal.rand = g_rand_new_with_seed (seed); + } else { + __nmtst_internal.rand = g_rand_new (); + + seed = g_rand_int (__nmtst_internal.rand); + g_rand_set_seed (__nmtst_internal.rand, seed); + } + __nmtst_internal.rand_seed = seed; + + g_message (">> initialize nmtst_get_rand() with seed=%u", seed); + } + return __nmtst_internal.rand; +} + +#define NMTST_SWAP(x,y) \ + G_STMT_START { \ + char __nmtst_swap_temp[sizeof(x) == sizeof(y) ? (signed) sizeof(x) : -1]; \ + memcpy(__nmtst_swap_temp, &y, sizeof(x)); \ + memcpy(&y, &x, sizeof(x)); \ + memcpy(&x, __nmtst_swap_temp, sizeof(x)); \ + } G_STMT_END + +inline guint32 nmtst_inet4_from_string (const char *str); +inline guint32 +nmtst_inet4_from_string (const char *str) +{ + guint32 addr; + int success; + + if (!str) + return 0; + + success = inet_pton (AF_INET, str, &addr); + + g_assert (success == 1); + + return addr; +} + +inline struct in6_addr *nmtst_inet6_from_string (const char *str); +inline struct in6_addr * +nmtst_inet6_from_string (const char *str) +{ + static struct in6_addr addr; + int success; + + if (!str) + addr = in6addr_any; + else { + success = inet_pton (AF_INET6, str, &addr); + g_assert (success == 1); + } + + return &addr; +} + +#ifdef NM_PLATFORM_H + +inline NMPlatformIP6Address *nmtst_platform_ip6_address (const char *address, const char *peer_address, guint plen); + +inline NMPlatformIP6Address * +nmtst_platform_ip6_address (const char *address, const char *peer_address, guint plen) +{ + static NMPlatformIP6Address addr; + + memset (&addr, 0, sizeof (addr)); + addr.address = *nmtst_inet6_from_string (address); + addr.peer_address = *nmtst_inet6_from_string (peer_address); + addr.plen = plen; + + return &addr; +} + + +inline NMPlatformIP6Address * +nmtst_platform_ip6_address_full (const char *address, const char *peer_address, guint plen, + int ifindex, NMPlatformSource source, guint32 timestamp, + guint32 lifetime, guint32 preferred, guint flags); + +inline NMPlatformIP6Address * +nmtst_platform_ip6_address_full (const char *address, const char *peer_address, guint plen, + int ifindex, NMPlatformSource source, guint32 timestamp, + guint32 lifetime, guint32 preferred, guint flags) +{ + NMPlatformIP6Address *addr = nmtst_platform_ip6_address (address, peer_address, plen); + + addr->ifindex = ifindex; + addr->source = source; + addr->timestamp = timestamp; + addr->lifetime = lifetime; + addr->preferred = preferred; + addr->flags = flags; + + return addr; +} + + +inline NMPlatformIP6Route * nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway); + +inline NMPlatformIP6Route * +nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) +{ + static NMPlatformIP6Route route; + + memset (&route, 0, sizeof (route)); + route.network = *nmtst_inet6_from_string (network); + route.plen = plen; + route.gateway = *nmtst_inet6_from_string (gateway); + + return &route; +} + + +inline NMPlatformIP6Route * +nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gateway, + int ifindex, NMPlatformSource source, + guint metric, guint mss); + +inline NMPlatformIP6Route * +nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gateway, + int ifindex, NMPlatformSource source, + guint metric, guint mss) +{ + NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway); + + route->ifindex = ifindex; + route->source = source; + route->metric = metric; + route->mss = mss; + + return route; +} + +#endif + + +#ifdef NM_IP4_CONFIG_H + +inline NMIP4Config *nmtst_ip4_config_clone (NMIP4Config *config); + +inline NMIP4Config * +nmtst_ip4_config_clone (NMIP4Config *config) +{ + NMIP4Config *copy = nm_ip4_config_new (); + + g_assert (copy); + g_assert (config); + nm_ip4_config_replace (copy, config, NULL); + return copy; +} + +#endif + + +#ifdef NM_IP6_CONFIG_H + +inline NMIP6Config *nmtst_ip6_config_clone (NMIP6Config *config); + +inline NMIP6Config * +nmtst_ip6_config_clone (NMIP6Config *config) +{ + NMIP6Config *copy = nm_ip6_config_new (); + + g_assert (copy); + g_assert (config); + nm_ip6_config_replace (copy, config, NULL); + return copy; +} + +#endif + + +#endif /* __NM_TEST_UTILS_H__ */ + diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 817b924334..b6e5a20203 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3062,6 +3062,9 @@ ip6_config_merge_and_apply (NMDevice *self, if (connection) nm_ip6_config_merge_setting (composite, nm_connection_get_setting_ip6_config (connection)); + nm_ip6_config_addresses_sort (composite, + priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + success = nm_device_set_ip6_config (self, composite, commit, out_reason); g_object_unref (composite); return success; @@ -7037,7 +7040,7 @@ update_ip_config (NMDevice *self, gboolean initial) /* IPv6 */ g_clear_object (&priv->ext_ip6_config); - priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf); + priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); if (priv->ext_ip6_config) { /* Check this before modifying ext_ip6_config */ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 8ca7c0cd05..36f5e72fdc 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -172,8 +172,115 @@ routes_are_duplicate (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, (!consider_gateway_and_metric || (IN6_ARE_ADDR_EQUAL (&a->gateway, &b->gateway) && a->metric == b->metric)); } +static gint +_addresses_sort_cmp_get_prio (const struct in6_addr *addr) +{ + if (IN6_IS_ADDR_V4MAPPED (addr)) + return 0; + if (IN6_IS_ADDR_V4COMPAT (addr)) + return 1; + if (IN6_IS_ADDR_UNSPECIFIED (addr)) + return 2; + if (IN6_IS_ADDR_LOOPBACK (addr)) + return 3; + if (IN6_IS_ADDR_LINKLOCAL (addr)) + return 4; + if (IN6_IS_ADDR_SITELOCAL (addr)) + return 5; + return 6; +} + +static gint +_addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) +{ + gint p1, p2, c; + gboolean perm1, perm2, tent1, tent2; + gboolean ipv6_privacy1, ipv6_privacy2; + const NMPlatformIP6Address *a1 = a, *a2 = b; + + /* tentative addresses are always sorted back... */ + /* sort tentative addresses after non-tentative. */ + tent1 = (a1->flags & IFA_F_TENTATIVE); + tent2 = (a2->flags & IFA_F_TENTATIVE); + if (tent1 != tent2) + return tent1 ? 1 : -1; + + /* Sort by address type. For example link local will + * be sorted *after* site local or global. */ + p1 = _addresses_sort_cmp_get_prio (&a1->address); + p2 = _addresses_sort_cmp_get_prio (&a2->address); + if (p1 != p2) + return p1 > p2 ? -1 : 1; + + ipv6_privacy1 = !!(a1->flags & (IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY)); + ipv6_privacy2 = !!(a2->flags & (IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY)); + if (ipv6_privacy1 || ipv6_privacy2) { + gboolean prefer_temp = ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR; + gboolean public1 = TRUE, public2 = TRUE; + + if (ipv6_privacy1) { + if (a1->flags & IFA_F_TEMPORARY) + public1 = prefer_temp; + else + public1 = !prefer_temp; + } + if (ipv6_privacy2) { + if (a2->flags & IFA_F_TEMPORARY) + public2 = prefer_temp; + else + public2 = !prefer_temp; + } + + if (public1 != public2) + return public1 ? -1 : 1; + } + + /* Sort the addresses based on their source. */ + if (a1->source != a2->source) + return a1->source > a2->source ? -1 : 1; + + /* sort permanent addresses before non-permanent. */ + perm1 = (a1->flags & IFA_F_PERMANENT); + perm2 = (a2->flags & IFA_F_PERMANENT); + if (perm1 != perm2) + return perm1 ? -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_ip6_config_addresses_sort (NMIP6Config *self, NMSettingIP6ConfigPrivacy use_temporary) +{ + NMIP6ConfigPrivate *priv; + size_t data_len = 0; + char *data_pre = NULL; + gboolean changed; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE); + + priv = NM_IP6_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_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary)); + + changed = memcmp (data_pre, priv->addresses->data, data_len) != 0; + g_free (data_pre); + + if (changed) { + _NOTIFY (self, PROP_ADDRESSES); + return TRUE; + } + } + return FALSE; +} + NMIP6Config * -nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf) +nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary) { NMIP6Config *config; NMIP6ConfigPrivate *priv; @@ -181,6 +288,7 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf) guint lowest_metric = G_MAXUINT; struct in6_addr old_gateway = IN6ADDR_ANY_INIT; gboolean has_gateway = FALSE; + gboolean notify_nameservers = FALSE; /* Slaves have no IP configuration */ if (nm_platform_link_get_master (ifindex) > 0) @@ -231,12 +339,14 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf) /* If the interface has the default route, and has IPv6 addresses, capture * nameservers from /etc/resolv.conf. */ - if (priv->addresses->len && has_gateway && capture_resolv_conf) { - if (nm_ip6_config_capture_resolv_conf (priv->nameservers, NULL)) - _NOTIFY (config, PROP_NAMESERVERS); - } + if (priv->addresses->len && has_gateway && capture_resolv_conf) + notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers, NULL); + + g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary)); /* actually, nobody should be connected to the signal, just to be sure, notify */ + if (notify_nameservers) + _NOTIFY (config, PROP_NAMESERVERS); _NOTIFY (config, PROP_ADDRESSES); _NOTIFY (config, PROP_ROUTES); if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &old_gateway)) diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index eb93d0789f..32a3b21fd0 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -58,7 +58,7 @@ void nm_ip6_config_export (NMIP6Config *config); const char * nm_ip6_config_get_dbus_path (const NMIP6Config *config); /* Integration with nm-platform and nm-setting */ -NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf); +NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); gboolean nm_ip6_config_commit (const NMIP6Config *config, int ifindex, int priority); void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting); void nm_ip6_config_update_setting (const NMIP6Config *config, NMSettingIP6Config *setting); @@ -83,6 +83,8 @@ void nm_ip6_config_del_address (NMIP6Config *config, guint i); guint nm_ip6_config_get_num_addresses (const NMIP6Config *config); const NMPlatformIP6Address *nm_ip6_config_get_address (const NMIP6Config *config, guint i); gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *address); +gboolean nm_ip6_config_addresses_sort (NMIP6Config *config, NMSettingIP6ConfigPrivacy use_temporary); + /* Routes */ void nm_ip6_config_reset_routes (NMIP6Config *config); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index c79ac20a17..21fa9b0c7a 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -24,61 +24,24 @@ #include "nm-ip6-config.h" -static void -addr_init (NMPlatformIP6Address *a, const char *addr, const char *peer, guint plen) -{ - memset (a, 0, sizeof (*a)); - g_assert (inet_pton (AF_INET6, addr, (void *) &a->address) == 1); - if (peer) - g_assert (inet_pton (AF_INET6, peer, (void *) &a->peer_address) == 1); - a->plen = plen; -} - -static void -route_new (NMPlatformIP6Route *route, const char *network, guint plen, const char *gw) -{ - g_assert (route); - memset (route, 0, sizeof (*route)); - g_assert (inet_pton (AF_INET6, network, (void *) &route->network) == 1); - route->plen = plen; - if (gw) - g_assert (inet_pton (AF_INET6, gw, (void *) &route->gateway) == 1); -} - -static void -addr_to_num (const char *addr, struct in6_addr *out_addr) -{ - memset (out_addr, 0, sizeof (*out_addr)); - g_assert (inet_pton (AF_INET6, addr, (void *) out_addr) == 1); -} +#include "nm-test-utils.h" static NMIP6Config * build_test_config (void) { NMIP6Config *config; - NMPlatformIP6Address addr; - NMPlatformIP6Route route; - struct in6_addr tmp; /* Build up the config to subtract */ config = nm_ip6_config_new (); - addr_init (&addr, "abcd:1234:4321::cdde", "1:2:3:4::5", 64); - nm_ip6_config_add_address (config, &addr); - - route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); - nm_ip6_config_add_route (config, &route); + nm_ip6_config_add_address (config, nmtst_platform_ip6_address ("abcd:1234:4321::cdde", "1:2:3:4::5", 64)); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2")); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234")); - route_new (&route, "2001:abba::", 16, "2001:abba::2234"); - nm_ip6_config_add_route (config, &route); + nm_ip6_config_set_gateway (config, nmtst_inet6_from_string ("3001:abba::3234")); - addr_to_num ("3001:abba::3234", &tmp); - nm_ip6_config_set_gateway (config, &tmp); - - addr_to_num ("1:2:3:4::1", &tmp); - nm_ip6_config_add_nameserver (config, &tmp); - addr_to_num ("1:2:3:4::2", &tmp); - nm_ip6_config_add_nameserver (config, &tmp); + nm_ip6_config_add_nameserver (config, nmtst_inet6_from_string ("1:2:3:4::1")); + nm_ip6_config_add_nameserver (config, nmtst_inet6_from_string ("1:2:3:4::2")); nm_ip6_config_add_domain (config, "foobar.com"); nm_ip6_config_add_domain (config, "baz.com"); nm_ip6_config_add_search (config, "blahblah.com"); @@ -91,8 +54,6 @@ static void test_subtract (void) { NMIP6Config *src, *dst; - NMPlatformIP6Address addr; - NMPlatformIP6Route route; const NMPlatformIP6Address *test_addr; const NMPlatformIP6Route *test_route; const char *expected_addr = "1122:3344:5566::7788"; @@ -110,15 +71,12 @@ test_subtract (void) /* add a couple more things to the test config */ dst = build_test_config (); - addr_init (&addr, expected_addr, NULL, expected_addr_plen); - nm_ip6_config_add_address (dst, &addr); - - route_new (&route, expected_route_dest, expected_route_plen, expected_route_next_hop); - nm_ip6_config_add_route (dst, &route); + nm_ip6_config_add_address (dst, nmtst_platform_ip6_address (expected_addr, NULL, expected_addr_plen)); + nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop)); - addr_to_num ("2222:3333:4444::5555", &expected_ns1); + expected_ns1 = *nmtst_inet6_from_string ("2222:3333:4444::5555"); nm_ip6_config_add_nameserver (dst, &expected_ns1); - addr_to_num ("2222:3333:4444::5556", &expected_ns2); + expected_ns2 = *nmtst_inet6_from_string ("2222:3333:4444::5556"); nm_ip6_config_add_nameserver (dst, &expected_ns2); nm_ip6_config_add_domain (dst, expected_domain); @@ -130,7 +88,7 @@ test_subtract (void) g_assert_cmpuint (nm_ip6_config_get_num_addresses (dst), ==, 1); test_addr = nm_ip6_config_get_address (dst, 0); g_assert (test_addr != NULL); - addr_to_num (expected_addr, &tmp); + tmp = *nmtst_inet6_from_string (expected_addr); g_assert (memcmp (&test_addr->address, &tmp, sizeof (tmp)) == 0); g_assert (memcmp (&test_addr->peer_address, &in6addr_any, sizeof (tmp)) == 0); g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); @@ -141,10 +99,10 @@ test_subtract (void) test_route = nm_ip6_config_get_route (dst, 0); g_assert (test_route != NULL); - addr_to_num (expected_route_dest, &tmp); + tmp = *nmtst_inet6_from_string (expected_route_dest); g_assert (memcmp (&test_route->network, &tmp, sizeof (tmp)) == 0); g_assert_cmpuint (test_route->plen, ==, expected_route_plen); - addr_to_num (expected_route_next_hop, &tmp); + tmp = *nmtst_inet6_from_string (expected_route_next_hop); g_assert (memcmp (&test_route->gateway, &tmp, sizeof (tmp)) == 0); g_assert_cmpuint (nm_ip6_config_get_num_nameservers (dst), ==, 2); @@ -171,7 +129,7 @@ test_compare_with_source (void) b = nm_ip6_config_new (); /* Address */ - addr_init (&addr, "1122:3344:5566::7788", NULL, 64); + addr = *nmtst_platform_ip6_address ("1122:3344:5566::7788", NULL, 64); addr.source = NM_PLATFORM_SOURCE_USER; nm_ip6_config_add_address (a, &addr); @@ -179,7 +137,7 @@ test_compare_with_source (void) nm_ip6_config_add_address (b, &addr); /* Route */ - route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); route.source = NM_PLATFORM_SOURCE_USER; nm_ip6_config_add_route (a, &route); @@ -203,7 +161,7 @@ test_add_address_with_source (void) a = nm_ip6_config_new (); /* Test that a higher priority source is not overwritten */ - addr_init (&addr, "1122:3344:5566::7788", NULL, 64); + addr = *nmtst_platform_ip6_address ("1122:3344:5566::7788", NULL, 64); addr.source = NM_PLATFORM_SOURCE_USER; nm_ip6_config_add_address (a, &addr); @@ -243,7 +201,7 @@ test_add_route_with_source (void) a = nm_ip6_config_new (); /* Test that a higher priority source is not overwritten */ - route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); route.source = NM_PLATFORM_SOURCE_USER; nm_ip6_config_add_route (a, &route); @@ -273,19 +231,106 @@ test_add_route_with_source (void) g_object_unref (a); } +static void +test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6ConfigPrivacy use_tempaddr, int repeat) +{ + 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); + int *idx = g_new (int, addr_count); + + /* initialize the array of indeces, and keep shuffling them for every @repeat iteration. */ + for (i = 0; i < addr_count; i++) + idx[i] = i; + + for (irepeat = 0; irepeat < repeat; irepeat++) { + /* randomly shuffle the addresses. */ + nm_ip6_config_reset_addresses (copy); + for (i = 0; i < addr_count; i++) { + int j = g_rand_int_range (nmtst_get_rand (), i, addr_count); + + NMTST_SWAP (idx[i], idx[j]); + nm_ip6_config_add_address (copy, nm_ip6_config_get_address (config, idx[i])); + } + + /* reorder them again */ + nm_ip6_config_addresses_sort (copy, use_tempaddr); + + /* check equality using nm_ip6_config_equal() */ + if (!nm_ip6_config_equal (copy, config)) { + g_message ("%s", "SORTING yields unexpected output:"); + for (i = 0; i < addr_count; i++) { + g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i))); + g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (copy, i))); + } + g_assert_not_reached (); + } + + /* also check equality using nm_ip6_config_replace() */ + g_assert (nm_ip6_config_replace (copy2, copy, NULL) == FALSE); + } + + g_free (idx); + g_object_unref (copy); + g_object_unref (copy2); +} + +static void +test_nm_ip6_config_addresses_sort (void) +{ + NMIP6Config *config = build_test_config (); + +#define ADDR_ADD(...) nm_ip6_config_add_address (config, nmtst_platform_ip6_address_full (__VA_ARGS__)) + + nm_ip6_config_reset_addresses (config); + ADDR_ADD("2607:f0d0:1002:51::4", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, 0); + ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, 0); + ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_PLATFORM_SOURCE_RDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); + ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("fec0::1", NULL, 128, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, 0); + ADDR_ADD("fe80::208:74ff:feda:625c", NULL, 128, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, 0); + ADDR_ADD("fe80::208:74ff:feda:625d", NULL, 128, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, 0); + ADDR_ADD("::1", NULL, 128, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, 0); + ADDR_ADD("2607:f0d0:1002:51::2", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, IFA_F_TENTATIVE); + test_nm_ip6_config_addresses_sort_check (config, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, 8); + test_nm_ip6_config_addresses_sort_check (config, NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED, 8); + test_nm_ip6_config_addresses_sort_check (config, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR, 8); + + nm_ip6_config_reset_addresses (config); + ADDR_ADD("2607:f0d0:1002:51::3", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::4", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, 0); + ADDR_ADD("2607:f0d0:1002:51::5", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, 0); + ADDR_ADD("2607:f0d0:1002:51::8", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::0", NULL, 64, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, IFA_F_SECONDARY); + ADDR_ADD("2607:f0d0:1002:51::6", NULL, 64, 0, NM_PLATFORM_SOURCE_RDISC, 0, 0, 0, IFA_F_MANAGETEMPADDR); + ADDR_ADD("fec0::1", NULL, 128, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, 0); + ADDR_ADD("fe80::208:74ff:feda:625c", NULL, 128, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, 0); + ADDR_ADD("fe80::208:74ff:feda:625d", NULL, 128, 0, NM_PLATFORM_SOURCE_KERNEL, 0, 0, 0, 0); + ADDR_ADD("::1", NULL, 128, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, 0); + ADDR_ADD("2607:f0d0:1002:51::2", NULL, 64, 0, NM_PLATFORM_SOURCE_USER, 0, 0, 0, IFA_F_TENTATIVE); + test_nm_ip6_config_addresses_sort_check (config, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, 8); + +#undef ADDR_ADD + g_object_unref (config); +} + /*******************************************/ +NMTST_DEFINE(); + int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); - - g_type_init (); + nmtst_init (&argc, &argv); g_test_add_func ("/ip6-config/subtract", test_subtract); g_test_add_func ("/ip6-config/compare-with-source", test_compare_with_source); g_test_add_func ("/ip6-config/add-address-with-source", test_add_address_with_source); g_test_add_func ("/ip6-config/add-route-with-source", test_add_route_with_source); + g_test_add_func ("/ip6-config/test_nm_ip6_config_addresses_sort", test_nm_ip6_config_addresses_sort); return g_test_run (); } |