From d1c528e64c198e5833c6bf3538404a388ec408b4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 20:31:47 +0200 Subject: [PATCH 01/11] device: fix regenerating IP settings for assumed connections Fixes: 06da3532428e3498c1e808ff8be1af48b540a6ff --- src/devices/nm-device.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 2568a100df..eaf9695fe7 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6856,12 +6856,21 @@ nm_device_set_ip4_config (NMDevice *self, if (nm_device_uses_generated_assumed_connection (self)) { NMConnection *connection = nm_device_get_applied_connection (self); + NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self)); NMSetting *s_ip4; g_object_freeze_notify (G_OBJECT (connection)); + g_object_freeze_notify (G_OBJECT (settings_connection)); + + nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP4_CONFIG); + s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); + nm_connection_add_setting (settings_connection, s_ip4); + nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); nm_connection_add_setting (connection, s_ip4); + + g_object_thaw_notify (G_OBJECT (settings_connection)); g_object_thaw_notify (G_OBJECT (connection)); } @@ -7014,12 +7023,21 @@ nm_device_set_ip6_config (NMDevice *self, if (nm_device_uses_generated_assumed_connection (self)) { NMConnection *connection = nm_device_get_applied_connection (self); + NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self)); NMSetting *s_ip6; g_object_freeze_notify (G_OBJECT (connection)); + g_object_freeze_notify (G_OBJECT (settings_connection)); + + nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP6_CONFIG); + s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); + nm_connection_add_setting (settings_connection, s_ip6); + nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); nm_connection_add_setting (connection, s_ip6); + + g_object_thaw_notify (G_OBJECT (settings_connection)); g_object_thaw_notify (G_OBJECT (connection)); } From f193d98ced90b0fd1317e03a5e89b369002c4376 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 10 Oct 2015 19:58:59 +0200 Subject: [PATCH 02/11] platform: refactor order of peer-address argument in ip_address_add() function The peer-address seems less important then the prefix-length. Also, nm_platform_ip4_address_delete() has the peer-address argument as last. Soon ip4_address_get() also receives a peer-address argument, so get the order right first. --- src/devices/nm-device.c | 2 +- src/platform/nm-fake-platform.c | 33 ++++++++++++++++-------- src/platform/nm-linux-platform.c | 4 +-- src/platform/nm-platform.c | 12 ++++----- src/platform/nm-platform.h | 42 ++++++++++++++++++++++--------- src/platform/tests/platform.c | 4 +-- src/platform/tests/test-address.c | 12 ++++----- src/platform/tests/test-cleanup.c | 4 +-- src/tests/test-route-manager.c | 4 +-- 9 files changed, 74 insertions(+), 43 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index eaf9695fe7..f86e751684 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -4862,8 +4862,8 @@ check_and_add_ipv6ll_addr (NMDevice *self) if (!nm_platform_ip6_address_add (NM_PLATFORM_GET, ip_ifindex, lladdr, - in6addr_any, 64, + in6addr_any, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)) { diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 8259eac6b5..800425ace7 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -87,9 +87,14 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) static void link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal); -static gboolean ip6_address_add (NMPlatform *platform, int ifindex, - struct in6_addr addr, struct in6_addr peer_addr, - int plen, guint32 lifetime, guint32 preferred, guint flags); +static gboolean ip6_address_add (NMPlatform *platform, + int ifindex, + struct in6_addr addr, + int plen, + struct in6_addr peer_addr, + guint32 lifetime, + guint32 preferred, + guint flags); static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen); /******************************************************************/ @@ -335,7 +340,7 @@ link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_s if (device->link.ifindex && !IN6_IS_ADDR_UNSPECIFIED (&device->ip6_lladdr)) { if (device->link.connected) - ip6_address_add (platform, device->link.ifindex, device->ip6_lladdr, in6addr_any, 64, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0); + ip6_address_add (platform, device->link.ifindex, in6addr_any, 64, device->ip6_lladdr, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0); else ip6_address_delete (platform, device->link.ifindex, device->ip6_lladdr, 64); } @@ -886,9 +891,13 @@ ip6_address_get_all (NMPlatform *platform, int ifindex) } static gboolean -ip4_address_add (NMPlatform *platform, int ifindex, - in_addr_t addr, in_addr_t peer_addr, - int plen, guint32 lifetime, guint32 preferred, +ip4_address_add (NMPlatform *platform, + int ifindex, + in_addr_t addr, + int plen, + in_addr_t peer_addr, + guint32 lifetime, + guint32 preferred, const char *label) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); @@ -929,9 +938,13 @@ ip4_address_add (NMPlatform *platform, int ifindex, } static gboolean -ip6_address_add (NMPlatform *platform, int ifindex, - struct in6_addr addr, struct in6_addr peer_addr, - int plen, guint32 lifetime, guint32 preferred, guint flags) +ip6_address_add (NMPlatform *platform, + int ifindex, + struct in6_addr addr, + int plen, + struct in6_addr peer_addr, + guint32 lifetime, + guint32 preferred, guint flags) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP6Address address; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index bf0df38d8b..1f6b1e22fe 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4238,8 +4238,8 @@ static gboolean ip4_address_add (NMPlatform *platform, int ifindex, in_addr_t addr, - in_addr_t peer_addr, int plen, + in_addr_t peer_addr, guint32 lifetime, guint32 preferred, const char *label) @@ -4260,8 +4260,8 @@ static gboolean ip6_address_add (NMPlatform *platform, int ifindex, struct in6_addr addr, - struct in6_addr peer_addr, int plen, + struct in6_addr peer_addr, guint32 lifetime, guint32 preferred, guint flags) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 9007fb4384..32c103a123 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1849,8 +1849,8 @@ gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, in_addr_t address, - in_addr_t peer_address, int plen, + in_addr_t peer_address, guint32 lifetime, guint32 preferred, const char *label) @@ -1879,15 +1879,15 @@ nm_platform_ip4_address_add (NMPlatform *self, _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr)); } - return klass->ip4_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, label); + return klass->ip4_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, label); } gboolean nm_platform_ip6_address_add (NMPlatform *self, int ifindex, struct in6_addr address, - struct in6_addr peer_address, int plen, + struct in6_addr peer_address, guint32 lifetime, guint32 preferred, guint flags) @@ -1914,7 +1914,7 @@ nm_platform_ip6_address_add (NMPlatform *self, _LOGD ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr)); } - return klass->ip6_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, flags); + return klass->ip6_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, flags); } gboolean @@ -2069,7 +2069,7 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) continue; - if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label)) + if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, known_address->peer_address, lifetime, preferred, known_address->label)) return FALSE; if (out_added_addresses) { @@ -2130,7 +2130,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, - known_address->peer_address, known_address->plen, + known_address->plen, known_address->peer_address, lifetime, preferred, known_address->flags)) return FALSE; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 756101c8fc..d68be070d2 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -513,13 +513,22 @@ typedef struct { GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex); GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex); - gboolean (*ip4_address_add) (NMPlatform *, int ifindex, - in_addr_t address, in_addr_t peer_address, int plen, - guint32 lifetime, guint32 preferred_lft, + gboolean (*ip4_address_add) (NMPlatform *, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred_lft, const char *label); - gboolean (*ip6_address_add) (NMPlatform *, int ifindex, - struct in6_addr address, struct in6_addr peer_address, int plen, - guint32 lifetime, guint32 preferred_lft, guint flags); + gboolean (*ip6_address_add) (NMPlatform *, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred_lft, + guint flags); gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, int plen); const NMPlatformIP4Address *(*ip4_address_get) (NMPlatform *, int ifindex, in_addr_t address, int plen); @@ -700,13 +709,22 @@ const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int i const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen); GArray *nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex); GArray *nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex); -gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, - in_addr_t address, in_addr_t peer_address, int plen, - guint32 lifetime, guint32 preferred_lft, +gboolean nm_platform_ip4_address_add (NMPlatform *self, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred_lft, const char *label); -gboolean nm_platform_ip6_address_add (NMPlatform *self, int ifindex, - struct in6_addr address, struct in6_addr peer_address, int plen, - guint32 lifetime, guint32 preferred_lft, guint flags); +gboolean nm_platform_ip6_address_add (NMPlatform *self, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred_lft, + guint flags); gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, int plen); gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index 31f36351f1..ec671eaa28 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -583,7 +583,7 @@ do_ip4_address_add (char **argv) guint32 lifetime = strtol (*argv++, NULL, 10); guint32 preferred = strtol (*argv++, NULL, 10); - gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, 0, plen, lifetime, preferred, NULL); + gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, plen, 0, lifetime, preferred, NULL); return value; } else return FALSE; @@ -601,7 +601,7 @@ do_ip6_address_add (char **argv) guint32 preferred = strtol (*argv++, NULL, 10); guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0; - gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, in6addr_any, plen, lifetime, preferred, flags); + gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, plen, in6addr_any, lifetime, preferred, flags); return value; } else return FALSE; diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 639fa0c80e..14cd9efdf2 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -65,12 +65,12 @@ test_ip4_address (void) /* Add address */ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); accept_signal (address_added); /* Add address again (aka update) */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -114,12 +114,12 @@ test_ip6_address (void) /* Add address */ g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags)); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); accept_signal (address_added); /* Add address again (aka update) */ - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags)); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -175,7 +175,7 @@ test_ip4_address_external (void) /* Add/delete conflict */ run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); accept_signal (address_added); /*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); @@ -212,7 +212,7 @@ test_ip6_address_external (void) /* Add/delete conflict */ run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags)); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); accept_signal (address_added); /*run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 0b825114aa..4ef6908588 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -43,8 +43,8 @@ test_cleanup_internal (void) g_assert (ifindex > 0); /* Add routes and addresses */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, 0, plen4, lifetime, preferred, NULL)); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, in6addr_any, plen6, lifetime, preferred, flags)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, 0, lifetime, preferred, NULL)); + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss)); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 86d52dff89..d5902af4bc 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -377,8 +377,8 @@ setup_dev0_ip6 (int ifindex) nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, *nmtst_inet6_from_string ("2001:db8:8086::666"), - in6addr_any, 64, + in6addr_any, 3600, 3600, 0); @@ -481,8 +481,8 @@ update_dev0_ip6 (int ifindex) nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, *nmtst_inet6_from_string ("2001:db8:8086::2"), - in6addr_any, 64, + in6addr_any, 3600, 3600, 0); From 44c43b4f5c5615f344a7013a168f6a3c8dc93feb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 15:12:45 +0200 Subject: [PATCH 03/11] platform: rename _CMP_POINTER() macro to _CMP_SELF() This name is better, because _CMP_SELF() is the first check of the two operands to catch pointer-equality and NULL values. --- src/platform/nm-platform.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 32c103a123..4cb57bed0b 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2692,7 +2692,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) return _nm_platform_to_string_buffer; } -#define _CMP_POINTER(a, b) \ +#define _CMP_SELF(a, b) \ G_STMT_START { \ if ((a) == (b)) \ return 0; \ @@ -2757,7 +2757,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, type); _CMP_FIELD_STR (a, b, name); @@ -2784,7 +2784,7 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD (a, b, address); @@ -2800,7 +2800,7 @@ nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4A int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, address); @@ -2816,7 +2816,7 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD (a, b, network); @@ -2832,7 +2832,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, network); @@ -2843,9 +2843,6 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route return 0; } -#undef _CMP_FIELD -#undef _CMP_FIELD_MEMCMP - /** * nm_platform_ip_address_cmp_expiry: * @a: a NMPlatformIPAddress to compare @@ -2864,7 +2861,7 @@ nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatfor { gint64 ta = 0, tb = 0; - _CMP_POINTER (a, b); + _CMP_SELF (a, b); if (a->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0) ta = G_MAXINT64; @@ -2897,8 +2894,6 @@ nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatfor return ta < tb ? -1 : 1; } -#undef _CMP_POINTER - const char * nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type) { From 560de03bf3ab3edbf30070f3da8f9ffec9bc805b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 16:07:39 +0200 Subject: [PATCH 04/11] ip4-config: allow IPv4 addresses that only differ by prefix-length Kernel treats IPv4 addresses with different netmask/prefix-length as different addresses. It is wrong to merge them together in nm_ip4_config_add_address(). For IPv6 addresses that is not the case and you cannot configure two IPv6 addresses that only differ by plen (on the same interface). --- src/nm-ip4-config.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 23af6aa713..55c5a7a68c 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -176,9 +176,10 @@ nm_ip4_config_capture_resolv_conf (GArray *nameservers, } static gboolean -addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b, gboolean consider_plen) +addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { - return a->address == b->address && (!consider_plen || a->plen == b->plen); + return a->address == b->address + && a->plen == b->plen; } static gboolean @@ -994,7 +995,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev if (nm_platform_ip4_address_cmp (src_addr = nm_ip4_config_get_address (src, i), dst_addr = nm_ip4_config_get_address (dst, i))) { are_equal = FALSE; - if (!addresses_are_duplicate (src_addr, dst_addr, TRUE)) { + if (!addresses_are_duplicate (src_addr, dst_addr)) { has_relevant_changes = TRUE; break; } @@ -1367,7 +1368,7 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) for (i = 0; i < priv->addresses->len; i++ ) { NMPlatformIP4Address *item = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - if (addresses_are_duplicate (item, new, FALSE)) { + if (addresses_are_duplicate (item, new)) { if (nm_platform_ip4_address_cmp (item, new) == 0) return; From df8e5da3c0f64d3a636b5007c3d0e866261d6e9f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 16:07:39 +0200 Subject: [PATCH 05/11] ip-config: refactor to use _addresses_get_index() function Also change the semantic of nm_ip6_config_address_exists() to ignore the prefix length. It seems more correct this way, but as there are no users of the function it doesn't actually matter. --- src/nm-ip4-config.c | 14 ++------------ src/nm-ip6-config.c | 23 +++++++---------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 55c5a7a68c..160c24ea1e 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -662,8 +662,7 @@ _addresses_get_index (const NMIP4Config *self, const NMPlatformIP4Address *addr) for (i = 0; i < priv->addresses->len; i++) { const NMPlatformIP4Address *a = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - if (addr->address == a->address && - addr->plen == a->plen) + if (addresses_are_duplicate (addr, a)) return (int) i; } return -1; @@ -1435,16 +1434,7 @@ gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *needle) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - guint i; - - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP4Address *haystack = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - - if (needle->address == haystack->address && needle->plen == haystack->plen) - return TRUE; - } - return FALSE; + return _addresses_get_index (config, needle) >= 0; } /******************************************************************/ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 4b18ceab80..ff4230126f 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -176,9 +176,9 @@ nm_ip6_config_capture_resolv_conf (GArray *nameservers, } static gboolean -addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b, gboolean consider_plen) +addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) { - return IN6_ARE_ADDR_EQUAL (&a->address, &b->address) && (!consider_plen || a->plen == b->plen); + return IN6_ARE_ADDR_EQUAL (&a->address, &b->address); } static gboolean @@ -731,7 +731,7 @@ _addresses_get_index (const NMIP6Config *self, const NMPlatformIP6Address *addr) for (i = 0; i < priv->addresses->len; i++) { const NMPlatformIP6Address *a = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - if (IN6_ARE_ADDR_EQUAL (&addr->address, &a->address)) + if (addresses_are_duplicate (a, addr)) return (int) i; } return -1; @@ -1012,7 +1012,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev if (nm_platform_ip6_address_cmp (src_addr = nm_ip6_config_get_address (src, i), dst_addr = nm_ip6_config_get_address (dst, i))) { are_equal = FALSE; - if (!addresses_are_duplicate (src_addr, dst_addr, TRUE)) { + if ( !addresses_are_duplicate (src_addr, dst_addr) + || src_addr->plen != dst_addr->plen) { has_relevant_changes = TRUE; break; } @@ -1283,7 +1284,7 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) for (i = 0; i < priv->addresses->len; i++ ) { NMPlatformIP6Address *item = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { + if (addresses_are_duplicate (item, new)) { if (nm_platform_ip6_address_cmp (item, new) == 0) return; @@ -1350,17 +1351,7 @@ gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *needle) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - guint i; - - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP6Address *haystack = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - - if ( IN6_ARE_ADDR_EQUAL (&needle->address, &haystack->address) - && needle->plen == haystack->plen) - return TRUE; - } - return FALSE; + return _addresses_get_index (config, needle) >= 0; } /******************************************************************/ From 8968e15eb7c8ae1aad42902764a990c8e930aaed Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 10 Oct 2015 17:48:32 +0200 Subject: [PATCH 06/11] platform: properly handle peer-address for IPv4 addresses Kernel allows to add the same IPv4 address that only differs by peer-address (IFL_ADDRESS): $ ip link add dummy type dummy $ ip address add 1.1.1.1 peer 1.1.1.3/24 dev dummy $ ip address add 1.1.1.1 peer 1.1.1.4/24 dev dummy RTNETLINK answers: File exists $ ip address add 1.1.1.1 peer 1.1.2.3/24 dev dummy $ ip address show dev dummy 2: dummy@NONE: mtu 1500 qdisc noop state DOWN group default link/ether 52:58:a7:1e:e8:93 brd ff:ff:ff:ff:ff:ff inet 1.1.1.1 peer 1.1.1.3/24 scope global dummy valid_lft forever preferred_lft forever inet 1.1.1.1 peer 1.1.2.3/24 scope global dummy valid_lft forever preferred_lft forever We must also consider peer-address, otherwise platform will treat two different addresses as one and the same. https://bugzilla.gnome.org/show_bug.cgi?id=756356 --- src/nm-ip4-config.c | 4 +- src/platform/nm-fake-platform.c | 13 ++++++- src/platform/nm-linux-platform.c | 9 ++--- src/platform/nm-platform.c | 61 +++++++++++++++++++++++++++++-- src/platform/nm-platform.h | 9 ++++- src/platform/nmp-object.c | 40 ++++++++++---------- src/platform/nmp-object.h | 2 +- src/platform/tests/platform.c | 6 +-- src/platform/tests/test-address.c | 16 ++++---- 9 files changed, 114 insertions(+), 46 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 160c24ea1e..bcef61dbb5 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -179,7 +179,8 @@ static gboolean addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { return a->address == b->address - && a->plen == b->plen; + && a->plen == b->plen + && nm_platform_ip4_address_equal_peer_net (a, b); } static gboolean @@ -2014,6 +2015,7 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); hash_u32 (sum, address->address); hash_u32 (sum, address->plen); + hash_u32 (sum, nm_platform_ip4_address_get_peer_net (address)); } for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 800425ace7..0732802ba0 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1031,15 +1031,24 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int } static const NMPlatformIP4Address * -ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; + NMPlatformIP4Address a = { + .ifindex = ifindex, + .address = addr, + .plen = plen, + .peer_address = peer_address, + }; for (i = 0; i < priv->ip4_addresses->len; i++) { NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); - if (address->ifindex == ifindex && address->plen == plen && address->address == addr) + if ( address->ifindex == ifindex + && address->plen == plen + && address->address == addr + && nm_platform_ip4_address_equal_peer_net (address, &a)) return address; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1f6b1e22fe..8b7a617e3a 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4252,7 +4252,7 @@ ip4_address_add (NMPlatform *platform, plen, lifetime, preferred, 0, label); return do_add_addrroute (platform, - nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen), + nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen, peer_addr), nlo); } @@ -4283,8 +4283,7 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, { NMPObject obj_needle; - nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen); - obj_needle.ip4_address.peer_address = peer_address; + nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen, peer_address); return do_delete_object (platform, &obj_needle, NULL); } @@ -4298,12 +4297,12 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int } static const NMPlatformIP4Address * -ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address) { NMPObject obj_needle; const NMPObject *obj; - nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen); + nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen, peer_address); obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle); if (nmp_object_is_visible (obj)) return &obj->ip4_address; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 4cb57bed0b..1469b5fee6 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1823,6 +1823,43 @@ _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size) /******************************************************************/ +in_addr_t +nm_platform_ip4_address_get_peer (const NMPlatformIP4Address *addr) +{ + return addr->peer_address ?: addr->address; +} + +const struct in6_addr * +nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr) +{ + if ( IN6_IS_ADDR_UNSPECIFIED (&addr->peer_address) + || IN6_ARE_ADDR_EQUAL (&addr->peer_address, &addr->address)) + return &addr->address; + return &addr->peer_address; +} + +in_addr_t +nm_platform_ip4_address_get_peer_net (const NMPlatformIP4Address *addr) +{ + return (addr->peer_address ?: addr->address) & nm_utils_ip4_prefix_to_netmask (addr->plen); +} + +gboolean +nm_platform_ip4_address_equal_peer_net (const NMPlatformIP4Address *addr1, const NMPlatformIP4Address *addr2) +{ + guint32 a1, a2; + + if (addr1->plen != addr2->plen) + return FALSE; + + /* For kernel, if the peer address is unset, that effectively means that + * the peer address equals the local address. */ + a1 = addr1->peer_address ? addr1->peer_address : addr1->address; + a2 = addr2->peer_address ? addr2->peer_address : addr2->address; + + return ((a1 ^ a2) & nm_utils_ip4_prefix_to_netmask (addr1->plen)) == 0; +} + GArray * nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex) { @@ -1957,13 +1994,13 @@ nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr a } const NMPlatformIP4Address * -nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen) +nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, guint32 peer_address) { _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (plen > 0, NULL); - return klass->ip4_address_get (self, ifindex, address, plen); + return klass->ip4_address_get (self, ifindex, address, plen, peer_address); } const NMPlatformIP6Address * @@ -1985,7 +2022,9 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address for (i = 0; i < len; i++) { NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); - if (candidate->address == address->address && candidate->plen == address->plen) { + if ( candidate->address == address->address + && candidate->plen == address->plen + && nm_platform_ip4_address_equal_peer_net (candidate, address)) { guint32 lifetime, preferred; if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, @@ -2702,6 +2741,12 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) return 1; \ } G_STMT_END +#define _CMP_DIRECT(a, b) \ + G_STMT_START { \ + if ((a) != (b)) \ + return ((a) < (b)) ? -1 : 1; \ + } G_STMT_END + #define _CMP_FIELD(a, b, field) \ G_STMT_START { \ if (((a)->field) != ((b)->field)) \ @@ -2784,12 +2829,20 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { + in_addr_t p_a, p_b; + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD (a, b, address); - _CMP_FIELD (a, b, peer_address); _CMP_FIELD (a, b, plen); + + /* a peer-address of zero is the same as setting it to address. + * Here we consider the full address, including the host-part. */ + p_a = nm_platform_ip4_address_get_peer (a); + p_b = nm_platform_ip4_address_get_peer (b); + _CMP_DIRECT (p_a, p_b); + _CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, lifetime); _CMP_FIELD (a, b, preferred); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d68be070d2..33fc480c92 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -531,7 +531,7 @@ typedef struct { guint flags); gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, int plen); - const NMPlatformIP4Address *(*ip4_address_get) (NMPlatform *, int ifindex, in_addr_t address, int plen); + const NMPlatformIP4Address *(*ip4_address_get) (NMPlatform *, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); const NMPlatformIP6Address *(*ip6_address_get) (NMPlatform *, int ifindex, struct in6_addr address, int plen); GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); @@ -705,7 +705,12 @@ guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel); gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); -const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen); +in_addr_t nm_platform_ip4_address_get_peer (const NMPlatformIP4Address *addr); +const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr); +in_addr_t nm_platform_ip4_address_get_peer_net (const NMPlatformIP4Address *addr); +gboolean nm_platform_ip4_address_equal_peer_net (const NMPlatformIP4Address *addr1, const NMPlatformIP4Address *addr2); + +const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen); GArray *nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex); GArray *nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 162b61feaf..1a35a352a0 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -296,19 +296,20 @@ _vt_cmd_obj_stackinit_id_link (NMPObject *obj, const NMPObject *src) } const NMPObject * -nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen) +nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen, guint32 peer_address) { nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP4_ADDRESS, NULL); obj->ip4_address.ifindex = ifindex; obj->ip4_address.address = address; obj->ip4_address.plen = plen; + obj->ip4_address.peer_address = peer_address; return obj; } static void _vt_cmd_obj_stackinit_id_ip4_address (NMPObject *obj, const NMPObject *src) { - nmp_object_stackinit_id_ip4_address (obj, src->ip_address.ifindex, src->ip4_address.address, src->ip_address.plen); + nmp_object_stackinit_id_ip4_address (obj, src->ip_address.ifindex, src->ip4_address.address, src->ip_address.plen, src->ip4_address.peer_address); } const NMPObject * @@ -425,17 +426,21 @@ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsiz { \ plat_type *const obj = (plat_type *) _obj; \ char buf1[NM_UTILS_INET_ADDRSTRLEN]; \ + char buf2[NM_UTILS_INET_ADDRSTRLEN]; \ \ (void) buf1; \ + (void) buf2; \ g_snprintf (buf, buf_len, \ __VA_ARGS__); \ return buf; \ } -_vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex); -_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen); -_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s/%d", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1), obj->plen); -_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); -_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); +_vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex); +_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen, + obj->peer_address && obj->peer_address != obj->address ? "," : "", + obj->peer_address && obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_platform_ip4_address_get_peer_net (obj), buf2) : ""); +_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s/%d", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1), obj->plen); +_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); +_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) @@ -533,6 +538,7 @@ _vt_cmd_plobj_id_copy (ip4_address, NMPlatformIP4Address, { dst->ifindex = src->ifindex; dst->plen = src->plen; dst->address = src->address; + dst->peer_address = src->peer_address; }); _vt_cmd_plobj_id_copy (ip6_address, NMPlatformIP6Address, { dst->ifindex = src->ifindex; @@ -619,7 +625,10 @@ _vt_cmd_plobj_id_equal (link, NMPlatformLink, _vt_cmd_plobj_id_equal (ip4_address, NMPlatformIP4Address, obj1->ifindex == obj2->ifindex && obj1->plen == obj2->plen - && obj1->address == obj2->address); + && obj1->address == obj2->address + /* for IPv4 addresses, you can add the same local address with differing peer-adddress + * (IFA_ADDRESS), provided that their net-part differs. */ + && nm_platform_ip4_address_equal_peer_net (obj1, obj2)); _vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address, obj1->ifindex == obj2->ifindex && obj1->plen == obj2->plen @@ -655,21 +664,17 @@ _vt_cmd_plobj_id_hash_##type (const NMPlatformObject *_obj) \ return hash; \ } _vt_cmd_plobj_id_hash (link, NMPlatformLink, { - /* libnl considers: - * .oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY, - */ hash = (guint) 3982791431u; hash = hash + ((guint) obj->ifindex); }) _vt_cmd_plobj_id_hash (ip4_address, NMPlatformIP4Address, { - /* libnl considers: - * .oo_id_attrs = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX | - * ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN), - */ hash = (guint) 3591309853u; hash = hash + ((guint) obj->ifindex); hash = hash * 33 + ((guint) obj->plen); hash = hash * 33 + ((guint) obj->address); + + /* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */ + hash = hash * 33 + ((guint) (nm_platform_ip4_address_get_peer_net (obj))); }) _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { hash = (guint) 2907861637u; @@ -678,11 +683,6 @@ _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { hash = hash * 33 + _id_hash_ip6_addr (&obj->address); }) _vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, { - /* libnl considers: - * .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | - * ROUTE_ATTR_TABLE | ROUTE_ATTR_DST | - * ROUTE_ATTR_PRIO), - */ hash = (guint) 2569857221u; hash = hash + ((guint) obj->ifindex); hash = hash * 33 + ((guint) obj->plen); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 5b1887b822..1367e8e67c 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -269,7 +269,7 @@ NMPObject *nmp_object_new_link (int ifindex); const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj); const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src); const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex); -const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen); +const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen, guint32 peer_address); const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address, int plen); const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, int plen, guint32 metric); const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, int plen, guint32 metric); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index ec671eaa28..08e89007ff 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -624,11 +624,11 @@ do_ip6_address_add (char **argv) } else \ return FALSE; \ } -#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0) ADDR_CMD_FULL (ip6, cmdname, FALSE) -#define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE) +#define ADDR_CMD(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, FALSE) +#define ADDR_CMD_PRINT(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, TRUE, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, TRUE) ADDR_CMD (delete) -ADDR_CMD_PRINT (get) +ADDR_CMD_PRINT (get, 0) static gboolean do_ip4_route_get_all (char **argv) diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 14cd9efdf2..902bc43dfb 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -64,9 +64,9 @@ test_ip4_address (void) inet_pton (AF_INET, IP4_ADDRESS, &addr); /* Add address */ - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); - g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_added); /* Add address again (aka update) */ @@ -85,7 +85,7 @@ test_ip4_address (void) /* Remove address */ g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_removed); /* Remove address again */ @@ -167,20 +167,20 @@ test_ip4_address_external (void) run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); wait_signal (address_added); - g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); wait_signal (address_removed); - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); /* Add/delete conflict */ run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", - IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); + IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); - g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_added); /*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0)); - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_removed);*/ free_signal (address_added); From cc654b9dd32550c9ca80ea33c296cc8e8e8c6c1c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 17:13:25 +0200 Subject: [PATCH 07/11] ip-config: expose IP peer address on D-Bus --- src/nm-ip4-config.c | 9 ++++++++- src/nm-ip6-config.c | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index bcef61dbb5..2f14a3aa6c 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -995,7 +995,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev if (nm_platform_ip4_address_cmp (src_addr = nm_ip4_config_get_address (src, i), dst_addr = nm_ip4_config_get_address (dst, i))) { are_equal = FALSE; - if (!addresses_are_duplicate (src_addr, dst_addr)) { + if ( !addresses_are_duplicate (src_addr, dst_addr) + || (nm_platform_ip4_address_get_peer (src_addr) != nm_platform_ip4_address_get_peer (dst_addr))) { has_relevant_changes = TRUE; break; } @@ -2162,6 +2163,12 @@ get_property (GObject *object, guint prop_id, g_variant_builder_add (&addr_builder, "{sv}", "prefix", g_variant_new_uint32 (address->plen)); + if ( address->peer_address + && address->peer_address != address->address) { + g_variant_builder_add (&addr_builder, "{sv}", + "peer", + g_variant_new_string (nm_utils_inet4_ntop (address->peer_address, NULL))); + } if (*address->label) { g_variant_builder_add (&addr_builder, "{sv}", diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index ff4230126f..573121d58d 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1013,7 +1013,9 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev dst_addr = nm_ip6_config_get_address (dst, i))) { are_equal = FALSE; if ( !addresses_are_duplicate (src_addr, dst_addr) - || src_addr->plen != dst_addr->plen) { + || src_addr->plen != dst_addr->plen + || !IN6_ARE_ADDR_EQUAL (nm_platform_ip6_address_get_peer (src_addr), + nm_platform_ip6_address_get_peer (dst_addr))) { has_relevant_changes = TRUE; break; } @@ -1931,6 +1933,12 @@ get_property (GObject *object, guint prop_id, g_variant_builder_add (&addr_builder, "{sv}", "prefix", g_variant_new_uint32 (address->plen)); + if ( !IN6_IS_ADDR_UNSPECIFIED (&address->peer_address) + && !IN6_ARE_ADDR_EQUAL (&address->peer_address, &address->address)) { + g_variant_builder_add (&addr_builder, "{sv}", + "peer", + g_variant_new_string (nm_utils_inet6_ntop (&address->peer_address, NULL))); + } g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); } From eab5a462b4e6491155a3d463739d9c6326af7e78 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 21:46:42 +0200 Subject: [PATCH 08/11] platform: fix comparing peer-address for IPv6 address in nm_platform_ip6_address_cmp() --- src/platform/nm-platform.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 1469b5fee6..e61315750b 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2747,6 +2747,13 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) return ((a) < (b)) ? -1 : 1; \ } G_STMT_END +#define _CMP_DIRECT_MEMCMP(a, b, size) \ + G_STMT_START { \ + int c = memcmp ((a), (b), (size)); \ + if (c != 0) \ + return c < 0 ? -1 : 1; \ + } G_STMT_END + #define _CMP_FIELD(a, b, field) \ G_STMT_START { \ if (((a)->field) != ((b)->field)) \ @@ -2853,11 +2860,17 @@ nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4A int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) { + const struct in6_addr *p_a, *p_b; + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, address); - _CMP_FIELD_MEMCMP (a, b, peer_address); + + p_a = nm_platform_ip6_address_get_peer (a); + p_b = nm_platform_ip6_address_get_peer (b); + _CMP_DIRECT_MEMCMP (p_a, p_b, sizeof (*p_a)); + _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, lifetime); From 6a5dab5c7cad6697dda00b3d98a78fffb53a770b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 11 Oct 2015 20:00:33 +0200 Subject: [PATCH 09/11] platform: fix id-equality for IPv6 address to ignore prefix-length For IPv6 addresses, the prefix-length is not part of the id. E.g. you cannot add two IPv6 addresses that only differ by plen. --- src/platform/nmp-object.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 1a35a352a0..abbde4c698 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -438,7 +438,7 @@ _vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen, obj->peer_address && obj->peer_address != obj->address ? "," : "", obj->peer_address && obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_platform_ip4_address_get_peer_net (obj), buf2) : ""); -_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s/%d", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1), obj->plen); +_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); _vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); _vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); @@ -542,7 +542,6 @@ _vt_cmd_plobj_id_copy (ip4_address, NMPlatformIP4Address, { }); _vt_cmd_plobj_id_copy (ip6_address, NMPlatformIP6Address, { dst->ifindex = src->ifindex; - dst->plen = src->plen; dst->address = src->address; }); _vt_cmd_plobj_id_copy (ip4_route, NMPlatformIP4Route, { @@ -631,7 +630,7 @@ _vt_cmd_plobj_id_equal (ip4_address, NMPlatformIP4Address, && nm_platform_ip4_address_equal_peer_net (obj1, obj2)); _vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address, obj1->ifindex == obj2->ifindex - && obj1->plen == obj2->plen + /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ && IN6_ARE_ADDR_EQUAL (&obj1->address, &obj2->address)); _vt_cmd_plobj_id_equal (ip4_route, NMPlatformIP4Route, obj1->ifindex == obj2->ifindex @@ -679,7 +678,7 @@ _vt_cmd_plobj_id_hash (ip4_address, NMPlatformIP4Address, { _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { hash = (guint) 2907861637u; hash = hash + ((guint) obj->ifindex); - hash = hash * 33 + ((guint) obj->plen); + /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ hash = hash * 33 + _id_hash_ip6_addr (&obj->address); }) _vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, { From 0d5428b1bdb4a533171e83b0387a0fe6b4fe8177 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 13 Oct 2015 19:48:17 +0200 Subject: [PATCH 10/11] test: add nmtst_get_rand_int() helper --- include/nm-test-utils.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/nm-test-utils.h b/include/nm-test-utils.h index 051da65d2e..fa795b5a99 100644 --- a/include/nm-test-utils.h +++ b/include/nm-test-utils.h @@ -577,6 +577,12 @@ nmtst_get_rand (void) return __nmtst_internal.rand; } +inline static guint32 +nmtst_get_rand_int (void) +{ + return g_rand_int (nmtst_get_rand ()); +} + inline static const char * nmtst_get_sudo_cmd (void) { From 06aafabf14e67e8e313e2f0c4b73de27cf3d7311 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 13 Oct 2015 19:49:09 +0200 Subject: [PATCH 11/11] platform/test: add test adding IPv4 addresses that only differ by their peer-address Also do a major cleanup of the tests: - Have utility functions in "test-common.h" with a new prefix "nmtstp_". The prefix indicates that these are test functions for platform. - Add functions to add/remove IP addresses that either use external iproute2 command or platform function itself. These commands also assert whether the command had the expected result. - Randomize, whether we use the external command for adding ip-addresses. Both approaches should yield the same result for linux-platform. I did this now for address-tests, but effectively this doubled all our previous tests to use both internal and external ways to configure the address. - Enable all address tests for fake-platform. They now automatically don't call external iproute2 but fallback to fake-platform implementation. This adds more coverage to the fake-platform, which we want to behave identical to linux-platform. - Setup a clean test device before every address-test. --- src/platform/nm-fake-platform.c | 6 +- src/platform/tests/test-address.c | 202 ++++++++--- src/platform/tests/test-common.c | 555 +++++++++++++++++++++++++++++- src/platform/tests/test-common.h | 50 ++- src/platform/tests/test-link.c | 20 +- 5 files changed, 753 insertions(+), 80 deletions(-) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 0732802ba0..b4f855eeef 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -908,7 +908,7 @@ ip4_address_add (NMPlatform *platform, address.source = NM_IP_CONFIG_SOURCE_KERNEL; address.ifindex = ifindex; address.address = addr; - address.peer_address = peer_addr; + address.peer_address = peer_addr && peer_addr != addr ? peer_addr : 0; address.plen = plen; address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = lifetime; @@ -925,6 +925,8 @@ ip4_address_add (NMPlatform *platform, continue; if (item->plen != address.plen) continue; + if (!nm_platform_ip4_address_equal_peer_net (item, &address)) + continue; memcpy (item, &address, sizeof (address)); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); @@ -954,7 +956,7 @@ ip6_address_add (NMPlatform *platform, address.source = NM_IP_CONFIG_SOURCE_KERNEL; address.ifindex = ifindex; address.address = addr; - address.peer_address = peer_addr; + address.peer_address = (IN6_IS_ADDR_UNSPECIFIED (&peer_addr) || IN6_ARE_ADDR_EQUAL (&addr, &peer_addr)) ? in6addr_any : peer_addr; address.plen = plen; address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = lifetime; diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 902bc43dfb..f37b05ceae 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -4,10 +4,17 @@ #define DEVICE_NAME "nm-test-device" #define IP4_ADDRESS "192.0.2.1" +#define IP4_ADDRESS_PEER "192.0.2.2" +#define IP4_ADDRESS_PEER2 "192.0.3.1" #define IP4_PLEN 24 #define IP6_ADDRESS "2001:db8:a:b:1:2:3:4" #define IP6_PLEN 64 +static int DEVICE_IFINDEX = -1; +static int EX = -1; + +/*****************************************************************************/ + static void ip4_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) { @@ -48,10 +55,12 @@ ip6_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, _LOGD ("Received signal '%s' %dth time.", data->name, data->received_count); } +/*****************************************************************************/ + static void -test_ip4_address (void) +test_ip4_address_general (void) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback, ifindex); SignalData *address_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_address_callback, ifindex); SignalData *address_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback, ifindex); @@ -65,12 +74,12 @@ test_ip4_address (void) /* Add address */ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_added); /* Add address again (aka update) */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime + 100, preferred + 50, NULL); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -84,12 +93,12 @@ test_ip4_address (void) g_array_unref (addresses); /* Remove address */ - g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0); g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_removed); /* Remove address again */ - g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0); free_signal (address_added); free_signal (address_changed); @@ -97,9 +106,9 @@ test_ip4_address (void) } static void -test_ip6_address (void) +test_ip6_address_general (void) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback, ifindex); SignalData *address_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_address_callback, ifindex); SignalData *address_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback, ifindex); @@ -114,12 +123,12 @@ test_ip6_address (void) /* Add address */ g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags)); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); accept_signal (address_added); /* Add address again (aka update) */ - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags)); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -133,12 +142,12 @@ test_ip6_address (void) g_array_unref (addresses); /* Remove address */ - g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + nmtstp_ip6_address_del (EX, ifindex, addr, IP6_PLEN); g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); accept_signal (address_removed); /* Remove address again */ - g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + nmtstp_ip6_address_del (EX, ifindex, addr, IP6_PLEN); free_signal (address_added); free_signal (address_changed); @@ -146,11 +155,11 @@ test_ip6_address (void) } static void -test_ip4_address_external (void) +test_ip4_address_general_2 (void) { + const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback); SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback); - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); in_addr_t addr; guint32 lifetime = 2000; guint32 preferred = 1000; @@ -161,38 +170,31 @@ test_ip4_address_external (void) /* Looks like addresses are not announced by kerenl when the interface * is down. Link-local IPv6 address is automatically added. */ - g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL)); + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, DEVICE_IFINDEX, NULL)); /* Add/delete notification */ - run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", - IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); - wait_signal (address_added); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL); + accept_signal (address_added); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); - run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); - wait_signal (address_removed); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0); + accept_signal (address_removed); g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); /* Add/delete conflict */ - run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", - IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred); - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); accept_signal (address_added); - /*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME); - g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0)); - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); - accept_signal (address_removed);*/ free_signal (address_added); free_signal (address_removed); } static void -test_ip6_address_external (void) +test_ip6_address_general_2 (void) { + const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback); SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback); - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); struct in6_addr addr; guint32 lifetime = 2000; guint32 preferred = 1000; @@ -201,51 +203,143 @@ test_ip6_address_external (void) inet_pton (AF_INET6, IP6_ADDRESS, &addr); /* Add/delete notification */ - run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", - IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred); - wait_signal (address_added); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, 0); + accept_signal (address_added); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME); - wait_signal (address_removed); + + nmtstp_ip6_address_del (EX, ifindex, addr, IP6_PLEN); + accept_signal (address_removed); g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); /* Add/delete conflict */ - run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d", - IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags)); - g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, 0); accept_signal (address_added); - /*run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME); - g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - wait_signal (address_removed);*/ + g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); + ensure_no_signal (address_added); + g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); free_signal (address_added); free_signal (address_removed); } +/*****************************************************************************/ + +static void +test_ip4_address_peer (void) +{ + const int ifindex = DEVICE_IFINDEX; + SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback); + SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback); + in_addr_t addr, addr_peer, addr_peer2; + guint32 lifetime = 2000; + guint32 preferred = 1000; + const NMPlatformIP4Address *a; + + inet_pton (AF_INET, IP4_ADDRESS, &addr); + inet_pton (AF_INET, IP4_ADDRESS_PEER, &addr_peer); + inet_pton (AF_INET, IP4_ADDRESS_PEER2, &addr_peer2); + g_assert (ifindex > 0); + + g_assert (addr != addr_peer); + + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL)); + accept_signals (address_removed, 0, G_MAXINT); + accept_signals (address_added, 0, G_MAXINT); + + /* Add/delete notification */ + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer, lifetime, preferred, NULL); + accept_signal (address_added); + g_assert ((a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer))); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2)); + + nmtstp_ip_address_assert_lifetime ((NMPlatformIPAddress *) a, -1, lifetime, preferred); + + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer2, lifetime, preferred, NULL); + accept_signal (address_added); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); + g_assert ((a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2))); + + nmtstp_ip_address_assert_lifetime ((NMPlatformIPAddress *) a, -1, lifetime, preferred); + + g_assert (addr != addr_peer); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr_peer); + accept_signal (address_removed); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2)); + + free_signal (address_added); + free_signal (address_removed); +} + +/*****************************************************************************/ + void init_tests (int *argc, char ***argv) { nmtst_init_with_logging (argc, argv, NULL, "ALL"); } -void -setup_tests (void) +/***************************************************************************** + * SETUP TESTS + *****************************************************************************/ + +typedef struct { + const char *testpath; + GTestFunc test_func; +} TestSetup; + +static void +_g_test_run (gconstpointer user_data) { - SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + const TestSetup *s = user_data; + int ifindex; + + _LOGt ("TEST: start %s", s->testpath); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); - accept_signal (link_added); - free_signal (link_added); + g_assert_cmpint (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL), ==, NM_PLATFORM_ERROR_SUCCESS); - g_test_add_func ("/address/internal/ip4", test_ip4_address); - g_test_add_func ("/address/internal/ip6", test_ip6_address); + ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + g_assert_cmpint (ifindex, >, 0); + g_assert_cmpint (DEVICE_IFINDEX, ==, -1); - if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform")) { - g_test_add_func ("/address/external/ip4", test_ip4_address_external); - g_test_add_func ("/address/external/ip6", test_ip6_address_external); - } + DEVICE_IFINDEX = ifindex; + EX = nmtstp_run_command_check_external_global (); + + s->test_func (); + + g_assert_cmpint (DEVICE_IFINDEX, ==, ifindex); + DEVICE_IFINDEX = -1; + + g_assert_cmpint (ifindex, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); + _LOGt ("TEST: finished %s", s->testpath); +} + +static void +_g_test_add_func (const char *testpath, + GTestFunc test_func) +{ + TestSetup *s; + + s = g_new0 (TestSetup, 1); + s->testpath = testpath; + s->test_func = test_func; + + g_test_add_data_func_full (testpath, s, _g_test_run, g_free); +} + +void +setup_tests (void) +{ + _g_test_add_func ("/address/ipv4/general", test_ip4_address_general); + _g_test_add_func ("/address/ipv6/general", test_ip6_address_general); + + _g_test_add_func ("/address/ipv4/general-2", test_ip4_address_general_2); + _g_test_add_func ("/address/ipv6/general-2", test_ip6_address_general_2); + + _g_test_add_func ("/address/ipv4/peer", test_ip4_address_peer); } diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index dd8ec80c53..e5308bcb75 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -10,9 +10,16 @@ #define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)" #define SIGNAL_DATA_ARG(data) (data)->name, nm_platform_signal_change_type_to_string ((data)->change_type), (data)->ifindex, (data)->ifname ? " ifname '" : "", (data)->ifname ? (data)->ifname : "", (data)->ifname ? "'" : "", (data)->received_count +typedef struct { + union { + guint8 addr_ptr[1]; + in_addr_t addr4; + struct in6_addr addr6; + }; +} IPAddr; gboolean -nmtst_platform_is_root_test (void) +nmtstp_is_root_test (void) { NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare") return (SETUP == nm_linux_platform_setup); @@ -20,9 +27,9 @@ nmtst_platform_is_root_test (void) } gboolean -nmtst_platform_is_sysfs_writable (void) +nmtstp_is_sysfs_writable (void) { - return !nmtst_platform_is_root_test () + return !nmtstp_is_root_test () || (access ("/sys/devices", W_OK) == 0); } @@ -69,6 +76,19 @@ _ensure_no_signal (const char *file, int line, const char *func, SignalData *dat g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal 0 times: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); } +void +_accept_or_wait_signal (const char *file, int line, const char *func, SignalData *data) +{ + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): accept-or-wait signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); + if (data->received_count == 0) { + data->loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (data->loop); + g_clear_pointer (&data->loop, g_main_loop_unref); + } + + _accept_signal (file, line, func, data); +} + void _wait_signal (const char *file, int line, const char *func, SignalData *data) { @@ -253,21 +273,534 @@ _assert_ip4_route_exists (const char *file, guint line, const char *func, gboole } } -void -run_command (const char *format, ...) +int +nmtstp_run_command (const char *format, ...) { - char *command; + int result; + gs_free char *command = NULL; va_list ap; va_start (ap, format); command = g_strdup_vprintf (format, ap); va_end (ap); + _LOGD ("Running command: %s", command); - g_assert (!system (command)); - _LOGD ("Command finished."); - g_free (command); + result = system (command); + _LOGD ("Command finished: result=%d", result); + + return result; } +/*****************************************************************************/ + +typedef struct { + GMainLoop *loop; + gboolean timeout; + guint id; +} WaitForSignalData; + +static void +_wait_for_signal_cb (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + NMPlatformLink *plink, + NMPlatformSignalChangeType change_type, + NMPlatformReason reason, + gpointer user_data) +{ + WaitForSignalData *data = user_data; + + g_main_loop_quit (data->loop); +} + +static gboolean +_wait_for_signal_timeout (gpointer user_data) +{ + WaitForSignalData *data = user_data; + + data->timeout = TRUE; + data->id = 0; + g_main_loop_quit (data->loop); + return G_SOURCE_REMOVE; +} + +gboolean +nmtstp_wait_for_signal (guint timeout_ms) +{ + WaitForSignalData data = { 0 }; + + guint id_link, id_ip4_address, id_ip6_address, id_ip4_route, id_ip6_route; + + data.loop = g_main_loop_new (NULL, FALSE); + + id_link = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip4_address = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip6_address = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip4_route = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip6_route = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + + if (timeout_ms != 0) + data.id = g_timeout_add (timeout_ms, _wait_for_signal_timeout, &data); + + g_main_loop_run (data.loop); + + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_link)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip4_address)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip6_address)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip4_route)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip6_route)); + + if (nm_clear_g_source (&data.id)) + g_assert (timeout_ms != 0 && !data.timeout); + + g_clear_pointer (&data.loop, g_main_loop_unref); + + return !data.timeout; +} + +gboolean +nmtstp_wait_for_signal_until (gint64 until_ms) +{ + gint64 now; + + while (TRUE) { + now = nm_utils_get_monotonic_timestamp_ms (); + + if (until_ms < now) + return FALSE; + + if (nmtstp_wait_for_signal (MAX (1, until_ms - now))) + return TRUE; + } +} + +int +nmtstp_run_command_check_external_global (void) +{ + if (!nmtstp_is_root_test ()) + return FALSE; + switch (nmtst_get_rand_int () % 3) { + case 0: + return -1; + case 1: + return FALSE; + default: + return TRUE; + } +} + +gboolean +nmtstp_run_command_check_external (int external_command) +{ + if (external_command != -1) { + g_assert (NM_IN_SET (external_command, FALSE, TRUE)); + g_assert (!external_command || nmtstp_is_root_test ()); + return !!external_command; + } + if (!nmtstp_is_root_test ()) + return FALSE; + return (nmtst_get_rand_int () % 2) == 0; +} + +#define CHECK_LIFETIME_MAX_DIFF 2 + +gboolean +nmtstp_ip_address_check_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred) +{ + gint64 offset; + int i; + + g_assert (addr); + + if (now == -1) + now = nm_utils_get_monotonic_timestamp_s (); + g_assert (now > 0); + + g_assert (expected_preferred <= expected_lifetime); + + if ( expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT) { + return addr->timestamp == 0 + && addr->lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && addr->preferred == NM_PLATFORM_LIFETIME_PERMANENT; + } + + if (addr->timestamp == 0) + return FALSE; + + offset = (gint64) now - addr->timestamp; + + for (i = 0; i < 2; i++) { + guint32 lft = i ? expected_lifetime : expected_preferred; + guint32 adr = i ? addr->lifetime : addr->preferred; + + if (lft == NM_PLATFORM_LIFETIME_PERMANENT) { + if (adr != NM_PLATFORM_LIFETIME_PERMANENT) + return FALSE; + } else { + if ( adr - offset <= lft - CHECK_LIFETIME_MAX_DIFF + || adr - offset >= lft + CHECK_LIFETIME_MAX_DIFF) + return FALSE; + } + } + return TRUE; +} + +void +nmtstp_ip_address_assert_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred) +{ + gint64 n = now; + gint64 offset; + int i; + + g_assert (addr); + + if (now == -1) + now = nm_utils_get_monotonic_timestamp_s (); + g_assert (now > 0); + + g_assert (expected_preferred <= expected_lifetime); + + if ( expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT) { + g_assert_cmpint (addr->timestamp, ==, 0); + g_assert_cmpint (addr->lifetime, ==, NM_PLATFORM_LIFETIME_PERMANENT); + g_assert_cmpint (addr->preferred, ==, NM_PLATFORM_LIFETIME_PERMANENT); + return; + } + + g_assert_cmpint (addr->timestamp, >, 0); + g_assert_cmpint (addr->timestamp, <=, now); + + offset = (gint64) now - addr->timestamp; + g_assert_cmpint (offset, >=, 0); + + for (i = 0; i < 2; i++) { + guint32 lft = i ? expected_lifetime : expected_preferred; + guint32 adr = i ? addr->lifetime : addr->preferred; + + if (lft == NM_PLATFORM_LIFETIME_PERMANENT) + g_assert_cmpint (adr, ==, NM_PLATFORM_LIFETIME_PERMANENT); + else { + g_assert_cmpint (adr, <=, lft); + g_assert_cmpint (offset, <=, adr); + g_assert_cmpint (adr - offset, <=, lft + CHECK_LIFETIME_MAX_DIFF); + g_assert_cmpint (adr - offset, >=, lft - CHECK_LIFETIME_MAX_DIFF); + } + } + + g_assert (nmtstp_ip_address_check_lifetime (addr, n, expected_lifetime, expected_preferred)); +} + +static void +_ip_address_add (gboolean external_command, + gboolean is_v4, + int ifindex, + const IPAddr *address, + int plen, + const IPAddr *peer_address, + guint32 lifetime, + guint32 preferred, + const char *label, + guint flags) +{ + gint64 end_time; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + const char *ifname; + gs_free char *s_valid = NULL; + gs_free char *s_preferred = NULL; + gs_free char *s_label = NULL; + char b1[NM_UTILS_INET_ADDRSTRLEN], b2[NM_UTILS_INET_ADDRSTRLEN]; + + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + g_assert (ifname); + + if (peer_address == address) + peer_address = 0; + + if (lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + s_valid = g_strdup_printf (" valid_lft %d", lifetime); + if (preferred != NM_PLATFORM_LIFETIME_PERMANENT) + s_preferred = g_strdup_printf (" preferred_lft %d", preferred); + if (label) + s_label = g_strdup_printf ("%s:%s", ifname, label); + + if (is_v4) { + g_assert (flags == 0); + nmtstp_run_command_check ("ip address change %s%s%s/%d dev %s%s%s%s", + nm_utils_inet4_ntop (address->addr4, b1), + peer_address->addr4 ? " peer " : "", + peer_address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "", + plen, + ifname, + s_valid ?: "", + s_preferred ?: "", + s_label ?: ""); + } else { + g_assert (label == NULL); + + /* flags not implemented (yet) */ + g_assert (flags == 0); + nmtstp_run_command_check ("ip address change %s%s%s/%d dev %s%s%s%s", + nm_utils_inet6_ntop (&address->addr6, b1), + !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? " peer " : "", + !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? nm_utils_inet6_ntop (&peer_address->addr6, b2) : "", + plen, + ifname, + s_valid ?: "", + s_preferred ?: "", + s_label ?: ""); + } + } else { + gboolean success; + + if (is_v4) { + g_assert (flags == 0); + success = nm_platform_ip4_address_add (NM_PLATFORM_GET, + ifindex, + address->addr4, + plen, + peer_address->addr4, + lifetime, + preferred, + label); + } else { + g_assert (label == NULL); + success = nm_platform_ip6_address_add (NM_PLATFORM_GET, + ifindex, + address->addr6, + plen, + peer_address->addr6, + lifetime, + preferred, + flags); + } + g_assert (success); + } + + /* Let's wait until we see the address. */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + + if (external_command) + nm_platform_process_events (NM_PLATFORM_GET); + + /* let's wait until we see the address as we added it. */ + if (is_v4) { + const NMPlatformIP4Address *a; + + g_assert (flags == 0); + a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); + if ( a + && nm_platform_ip4_address_get_peer (a) == (peer_address->addr4 ? peer_address->addr4 : address->addr4) + && nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred) + && strcmp (a->label, label ?: "") == 0) + break; + } else { + const NMPlatformIP6Address *a; + + g_assert (label == NULL); + g_assert (flags == 0); + + a = nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, address->addr6, plen); + if ( a + && !memcmp (nm_platform_ip6_address_get_peer (a), + (IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) || IN6_ARE_ADDR_EQUAL (&address->addr6, &peer_address->addr6)) + ? &address->addr6 : &peer_address->addr6, + sizeof (struct in6_addr)) + && nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred)) + break; + } + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + /* timeout? */ + g_assert (nm_utils_get_monotonic_timestamp_ms () < end_time); + + g_assert (nmtstp_wait_for_signal_until (end_time)); + } while (TRUE); +} + +void +nmtstp_ip4_address_add (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred, + const char *label) +{ + _ip_address_add (external_command, + TRUE, + ifindex, + (IPAddr *) &address, + plen, + (IPAddr *) &peer_address, + lifetime, + preferred, + label, + 0); +} + +void +nmtstp_ip6_address_add (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred, + guint flags) +{ + _ip_address_add (external_command, + FALSE, + ifindex, + (IPAddr *) &address, + plen, + (IPAddr *) &peer_address, + lifetime, + preferred, + NULL, + flags); +} + +static void +_ip_address_del (gboolean external_command, + gboolean is_v4, + int ifindex, + const IPAddr *address, + int plen, + const IPAddr *peer_address) +{ + gint64 end_time; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + const char *ifname; + char b1[NM_UTILS_INET_ADDRSTRLEN], b2[NM_UTILS_INET_ADDRSTRLEN]; + int success; + gboolean had_address; + + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + g_assert (ifname); + + if (peer_address == address) + peer_address = 0; + + /* let's wait until we see the address as we added it. */ + if (is_v4) + had_address = !!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); + else + had_address = !!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, address->addr6, plen); + + if (is_v4) { + success = nmtstp_run_command ("ip address delete %s%s%s/%d dev %s", + nm_utils_inet4_ntop (address->addr4, b1), + peer_address->addr4 ? " peer " : "", + peer_address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "", + plen, + ifname); + } else { + g_assert (!peer_address); + success = nmtstp_run_command ("ip address delete %s/%d dev %s", + nm_utils_inet6_ntop (&address->addr6, b1), + plen, + ifname); + } + g_assert (success == 0 || !had_address); + } else { + gboolean success; + + if (is_v4) { + success = nm_platform_ip4_address_delete (NM_PLATFORM_GET, + ifindex, + address->addr4, + plen, + peer_address->addr4); + } else { + g_assert (!peer_address); + success = nm_platform_ip6_address_delete (NM_PLATFORM_GET, + ifindex, + address->addr6, + plen); + } + g_assert (success); + } + + /* Let's wait until we get the result */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + if (external_command) + nm_platform_process_events (NM_PLATFORM_GET); + + /* let's wait until we see the address as we added it. */ + if (is_v4) { + const NMPlatformIP4Address *a; + + a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); + if (!a) + break; + } else { + const NMPlatformIP6Address *a; + + a = nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, address->addr6, plen); + if (!a) + break; + } + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + /* timeout? */ + g_assert (nm_utils_get_monotonic_timestamp_ms () < end_time); + + g_assert (nmtstp_wait_for_signal_until (end_time)); + } while (TRUE); +} + +void +nmtstp_ip4_address_del (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address) +{ + _ip_address_del (external_command, + TRUE, + ifindex, + (IPAddr *) &address, + plen, + (IPAddr *) &peer_address); +} + +void +nmtstp_ip6_address_del (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen) +{ + _ip_address_del (external_command, + FALSE, + ifindex, + (IPAddr *) &address, + plen, + NULL); +} + +/*****************************************************************************/ + NMTST_DEFINE(); static gboolean @@ -318,7 +851,7 @@ main (int argc, char **argv) init_tests (&argc, &argv); - if ( nmtst_platform_is_root_test () + if ( nmtstp_is_root_test () && (geteuid () != 0 || getegid () != 0)) { if ( g_getenv ("NMTST_FORCE_REAL_ROOT") || !unshare_user ()) { @@ -335,7 +868,7 @@ main (int argc, char **argv) } } - if (nmtst_platform_is_root_test () && !g_getenv ("NMTST_NO_UNSHARE")) { + if (nmtstp_is_root_test () && !g_getenv ("NMTST_NO_UNSHARE")) { int errsv; if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) { diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 3a2f6d5f13..626e9d2fde 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -43,8 +43,8 @@ typedef struct { const char *ifname; } SignalData; -gboolean nmtst_platform_is_root_test (void); -gboolean nmtst_platform_is_sysfs_writable (void); +gboolean nmtstp_is_root_test (void); +gboolean nmtstp_is_sysfs_writable (void); SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname); #define add_signal(name, change_type, callback) add_signal_full (name, change_type, (GCallback) callback, 0, NULL) @@ -53,11 +53,13 @@ SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change void _accept_signal (const char *file, int line, const char *func, SignalData *data); void _accept_signals (const char *file, int line, const char *func, SignalData *data, int min, int max); void _wait_signal (const char *file, int line, const char *func, SignalData *data); +void _accept_or_wait_signal (const char *file, int line, const char *func, SignalData *data); void _ensure_no_signal (const char *file, int line, const char *func, SignalData *data); void _free_signal (const char *file, int line, const char *func, SignalData *data); #define accept_signal(data) _accept_signal(__FILE__, __LINE__, G_STRFUNC, data) #define accept_signals(data, min, max) _accept_signals(__FILE__, __LINE__, G_STRFUNC, data, min, max) #define wait_signal(data) _wait_signal(__FILE__, __LINE__, G_STRFUNC, data) +#define accept_or_wait_signal(data) _accept_or_wait_signal(__FILE__, __LINE__, G_STRFUNC, data) #define ensure_no_signal(data) _ensure_no_signal(__FILE__, __LINE__, G_STRFUNC, data) #define free_signal(data) _free_signal(__FILE__, __LINE__, G_STRFUNC, data) @@ -68,7 +70,49 @@ void _assert_ip4_route_exists (const char *file, guint line, const char *func, g void link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data); -void run_command (const char *format, ...); +int nmtstp_run_command (const char *format, ...) __attribute__((__format__ (__printf__, 1, 2))); +#define nmtstp_run_command_check(format, ...) do { g_assert_cmpint (nmtstp_run_command (format, __VA_ARGS__), ==, 0); } while (0) + +gboolean nmtstp_wait_for_signal (guint timeout_ms); +gboolean nmtstp_wait_for_signal_until (gint64 until_ms); + +int nmtstp_run_command_check_external_global (void); +gboolean nmtstp_run_command_check_external (int external_command); + +gboolean nmtstp_ip_address_check_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred); +void nmtstp_ip_address_assert_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred); +void nmtstp_ip4_address_add (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred, + const char *label); +void nmtstp_ip6_address_add (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred, + guint flags); +void nmtstp_ip4_address_del (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address); +void nmtstp_ip6_address_del (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen); + void init_tests (int *argc, char ***argv); void setup_tests (void); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index f9645d855e..e6ab6bdd84 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -262,7 +262,7 @@ test_slave (int master, int type, SignalData *master_changed) /* Set slave option */ switch (type) { case NM_LINK_TYPE_BRIDGE: - if (nmtst_platform_is_sysfs_writable ()) { + if (nmtstp_is_sysfs_writable ()) { g_assert (nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789")); value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, "priority"); g_assert_cmpstr (value, ==, "789"); @@ -341,7 +341,7 @@ test_software (NMLinkType link_type, const char *link_typename) /* Set master option */ switch (link_type) { case NM_LINK_TYPE_BRIDGE: - if (nmtst_platform_is_sysfs_writable ()) { + if (nmtstp_is_sysfs_writable ()) { g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789")); value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay"); g_assert_cmpstr (value, ==, "789"); @@ -349,7 +349,7 @@ test_software (NMLinkType link_type, const char *link_typename) } break; case NM_LINK_TYPE_BOND: - if (nmtst_platform_is_sysfs_writable ()) { + if (nmtstp_is_sysfs_writable ()) { g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup")); value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "mode"); /* When reading back, the output looks slightly different. */ @@ -408,7 +408,7 @@ test_bridge (void) static void test_bond (void) { - if (nmtst_platform_is_root_test () && + if (nmtstp_is_root_test () && !g_file_test ("/proc/1/net/bonding", G_FILE_TEST_IS_DIR) && system("modprobe --show bonding") != 0) { g_test_skip ("Skipping test for bonding: bonding module not available"); @@ -519,7 +519,7 @@ test_external (void) SignalData *link_changed, *link_removed; int ifindex; - run_command ("ip link add %s type %s", DEVICE_NAME, "dummy"); + nmtstp_run_command_check ("ip link add %s type %s", DEVICE_NAME, "dummy"); wait_signal (link_added); g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); @@ -543,24 +543,24 @@ test_external (void) g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s up", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s up", DEVICE_NAME); wait_signal (link_changed); g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s down", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s down", DEVICE_NAME); wait_signal (link_changed); g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s arp on", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s arp on", DEVICE_NAME); wait_signal (link_changed); g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s arp off", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s arp off", DEVICE_NAME); wait_signal (link_changed); g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex)); - run_command ("ip link del %s", DEVICE_NAME); + nmtstp_run_command_check ("ip link del %s", DEVICE_NAME); wait_signal (link_removed); accept_signals (link_changed, 0, 1); g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));