summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-10-13 19:49:09 +0200
committerThomas Haller <thaller@redhat.com>2015-10-14 13:16:23 +0200
commitb76d4f7f5c00e826045b03c81f56dba8490c52ef (patch)
treed9c96dc2c611de98902ff27961736829b9ee0730
parent0d5428b1bdb4a533171e83b0387a0fe6b4fe8177 (diff)
downloadNetworkManager-th/platform-ipv4-peer-address-bgo756356.tar.gz
platform/test: add test adding IPv4 addresses that only differ by their peer-addressth/platform-ipv4-peer-address-bgo756356
- move utility function to "test-common.h" with a new prefix "nmtstp_" indicating that these are test functions for platform. - add function to add/remove IP addresses that optionally use external iproute2 command or platform function itself. And add some assertions there to check whether the functions behaved correctly. - randomize, whether we use the external function for adding ip-addresses. In fact, both ways should yield the same result for linux-platform. - also enable the address tests for fake-platform. They now automatically don't call external iproute2. - create a clean test device before every test.
-rw-r--r--src/platform/nm-fake-platform.c6
-rw-r--r--src/platform/tests/test-address.c173
-rw-r--r--src/platform/tests/test-common.c528
-rw-r--r--src/platform/tests/test-common.h49
-rw-r--r--src/platform/tests/test-link.c20
5 files changed, 711 insertions, 65 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..3c62e55139 100644
--- a/src/platform/tests/test-address.c
+++ b/src/platform/tests/test-address.c
@@ -4,10 +4,14 @@
#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 void
ip4_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
{
@@ -51,7 +55,7 @@ ip6_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex,
static void
test_ip4_address (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);
@@ -99,7 +103,7 @@ test_ip4_address (void)
static void
test_ip6_address (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);
@@ -148,9 +152,9 @@ test_ip6_address (void)
static void
test_ip4_address_external (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,27 +165,21 @@ 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 (-1, 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 (-1, 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);
+ nmtstp_ip4_address_add (-1, ifindex, addr, IP4_PLEN, 0, 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, 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);
@@ -190,9 +188,9 @@ test_ip4_address_external (void)
static void
test_ip6_address_external (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 +199,148 @@ 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 (-1, 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 (-1, 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);
+ nmtstp_ip6_address_add (-1, 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));
+
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, 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_external_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 (-1, ifindex, addr, IP4_PLEN, addr_peer, lifetime, preferred, NULL);
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 ((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 (-1, 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 (-1, 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
+_test_setup_free (gpointer data)
+{
+ g_free (data);
+}
+
+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;
+
+ nm_log_trace (LOGD_PLATFORM, ">>> 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);
+
+ ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
+ g_assert_cmpint (ifindex, >, 0);
+ g_assert_cmpint (DEVICE_IFINDEX, ==, -1);
+
+ DEVICE_IFINDEX = ifindex;
+
+ 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));
+ nm_log_trace (LOGD_PLATFORM, ">>> 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, _test_setup_free);
+}
+
+void
+setup_tests (void)
+{
+ _g_test_add_func ("/address/internal/ip4", test_ip4_address);
+ _g_test_add_func ("/address/internal/ip6", test_ip6_address);
- g_test_add_func ("/address/internal/ip4", test_ip4_address);
- g_test_add_func ("/address/internal/ip6", test_ip6_address);
+ _g_test_add_func ("/address/external/ip4", test_ip4_address_external);
+ _g_test_add_func ("/address/external/ip6", test_ip6_address_external);
- 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);
- }
+ _g_test_add_func ("/address/external/ip4-peer", test_ip4_address_external_peer);
}
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index dd8ec80c53..3aa03fdff2 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);
}
@@ -70,6 +77,19 @@ _ensure_no_signal (const char *file, int line, const char *func, SignalData *dat
}
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)
{
_LOGD ("NMPlatformSignalAssert: %s:%d, %s(): wait signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
@@ -253,21 +273,507 @@ _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;
+ }
+}
+
+gboolean
+nmtstp_run_command_check_external (gboolean external_command)
+{
+ if (external_command != -1) {
+ 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;
+}
+
+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 - 2
+ || adr - offset >= lft + 2)
+ 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 + 2);
+ g_assert_cmpint (adr - offset, >=, lft - 2);
+ }
+ }
+
+ 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];
+
+ ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
+ g_assert (ifname);
+
+ if (peer_address == address)
+ peer_address = 0;
+
+ if (is_v4) {
+ 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);
+ nmtstp_run_command ("ip address delete %s/%d dev %s",
+ nm_utils_inet6_ntop (&address->addr6, b1),
+ plen,
+ ifname);
+ }
+ } 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 +824,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 +841,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..cab5e334fc 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,48 @@ 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);
+
+gboolean nmtstp_run_command_check_external (gboolean 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));