summaryrefslogtreecommitdiff
path: root/src/platform/tests/test-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/tests/test-common.c')
-rw-r--r--src/platform/tests/test-common.c294
1 files changed, 279 insertions, 15 deletions
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index b1947a6d11..34783c3ea4 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -25,6 +25,8 @@
#include <sys/wait.h>
#include <fcntl.h>
+#include "nm-platform-utils.h"
+
#include "test-common.h"
#define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)"
@@ -197,7 +199,7 @@ link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlat
/*****************************************************************************/
gboolean
-nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric)
+nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric, const guint32 *gateway)
{
gs_free char *arg_network = NULL;
const char *argv[] = {
@@ -216,6 +218,7 @@ nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32
gboolean success;
gs_free_error GError *error = NULL;
gs_free char *metric_pattern = NULL;
+ gs_free char *via_pattern = NULL;
g_assert (ifname && nm_utils_iface_valid_name (ifname));
g_assert (!strstr (ifname, " metric "));
@@ -253,6 +256,7 @@ nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32
g_assert (std_out);
metric_pattern = g_strdup_printf (" metric %u", metric);
+ via_pattern = gateway ? g_strdup_printf (" via %s", nm_utils_inet4_ntop (*gateway, NULL)) : NULL;
out = std_out;
while (out) {
char *eol = strchr (out, '\n');
@@ -264,45 +268,104 @@ nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32
continue;
if (metric == 0) {
- if (!strstr (line, " metric "))
- return TRUE;
+ if (strstr (line, " metric "))
+ continue;
+ } else {
+ p = strstr (line, metric_pattern);
+ if (!p || !NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0'))
+ continue;
}
- p = strstr (line, metric_pattern);
- if (p && NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0'))
- return TRUE;
+
+ if (gateway) {
+ if (*gateway == 0) {
+ if (strstr (line, " via "))
+ continue;
+ } else {
+ p = strstr (line, via_pattern);
+ if (!p || !NM_IN_SET (p[strlen (via_pattern)], ' ', '\0'))
+ continue;
+ }
+ }
+ return TRUE;
}
return FALSE;
}
void
-_nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric)
+_nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric, const guint32 *gateway)
{
int ifindex;
gboolean exists_checked;
+ char s_buf[NM_UTILS_INET_ADDRSTRLEN];
+ guint32 g = 0;
+ gboolean found_fuzzy = FALSE;
_init_platform (&platform, FALSE);
/* Check for existance of the route by spawning iproute2. Do this because platform
* code might be entirely borked, but we expect ip-route to give a correct result.
* If the ip command cannot be found, we accept this as success. */
- exists_checked = nmtstp_ip4_route_exists (ifname, network, plen, metric);
+ exists_checked = nmtstp_ip4_route_exists (ifname, network, plen, metric, gateway);
if (exists_checked != -1 && !exists_checked != !exists) {
- g_error ("[%s:%u] %s(): We expect the ip4 route %s/%d metric %u %s, but it %s",
+ g_error ("[%s:%u] %s(): We expect the ip4 route %s/%d%s metric %u %s, but it %s",
file, line, func,
- nm_utils_inet4_ntop (network, NULL), plen, metric,
+ nm_utils_inet4_ntop (network, NULL), plen,
+ gateway ? nm_sprintf_bufa (100, " gateway %s", nm_utils_inet4_ntop (*gateway, s_buf)) : " no-gateway",
+ metric,
exists ? "to exist" : "not to exist",
exists ? "doesn't" : "does");
}
ifindex = nm_platform_link_get_ifindex (platform, ifname);
g_assert (ifindex > 0);
- if (!nm_platform_ip4_route_get (platform, ifindex, network, plen, metric) != !exists) {
- g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u %s, but platform thinks %s",
+
+ if (gateway)
+ g = *gateway;
+ else {
+ gs_unref_array GArray *routes = NULL;
+ guint i;
+
+ routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
+ for (i = 0; routes && i < routes->len; i++) {
+ const NMPlatformIP4Route *r = &g_array_index (routes, NMPlatformIP4Route, i);
+
+ g_assert (r->ifindex == ifindex);
+ if ( r->network == network
+ && r->plen == plen
+ && r->metric == metric) {
+ g_assert (!found_fuzzy);
+ found_fuzzy = TRUE;
+ g = r->gateway;
+ }
+ }
+ if (found_fuzzy)
+ goto found;
+ if (exists) {
+ g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u %s, but platform thinks %s",
+ file, line, func,
+ nm_utils_inet4_ntop (network, NULL),
+ plen,
+ metric,
+ exists ? "exists" : "does not exist",
+ exists ? "it doesn't" : "it does");
+ }
+ return;
+ }
+found:
+ if (!nm_platform_ip4_route_get (platform, ifindex, network, plen, metric, g) != !exists) {
+ g_error ("[%s:%u] %s(): The ip4 route %s/%d via %s metric %u %s, but platform thinks %s",
file, line, func,
- nm_utils_inet4_ntop (network, NULL), plen, metric,
+ nm_utils_inet4_ntop (network, NULL),
+ plen,
+ nm_utils_inet4_ntop (g, s_buf),
+ metric,
exists ? "exists" : "does not exist",
exists ? "it doesn't" : "it does");
}
+
+ /* when we found the route via fuzzy-match (without gateway), we expect that
+ * exists and nm_platform_ip4_route_get() agree. */
+ g_assert (!found_fuzzy || exists);
}
/*****************************************************************************/
@@ -414,7 +477,7 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms)
const NMPlatformLink *
nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms)
{
- return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms);
+ return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms);
}
const NMPlatformLink *
@@ -443,7 +506,7 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType
const NMPlatformLink *
nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms)
{
- return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms);
+ return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms);
}
const NMPlatformLink *
@@ -458,6 +521,61 @@ nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NML
/*****************************************************************************/
+static const void *
+_wait_for_ip_route_until (NMPlatform *platform, int is_v4, int ifindex, const NMIPAddr *network, guint8 plen, guint32 metric, const NMIPAddr *gateway, gint64 until_ms)
+{
+ const void *plroute = NULL;
+ gint64 now;
+
+ _init_platform (&platform, FALSE);
+
+ while (TRUE) {
+ now = nm_utils_get_monotonic_timestamp_ms ();
+
+ if (is_v4)
+ plroute = nm_platform_ip4_route_get (platform, ifindex, network->addr4, plen, metric, gateway->addr4);
+ else {
+ plroute = nm_platform_ip6_route_get (platform, ifindex,
+ network ? network->addr6 : in6addr_any,
+ plen, metric,
+ gateway ? &gateway->addr6 : &in6addr_any);
+ }
+ if (plroute)
+ return plroute;
+
+ if (until_ms < now)
+ return NULL;
+
+ nmtstp_wait_for_signal (platform, MAX (1, until_ms - now));
+ }
+}
+
+const NMPlatformIP4Route *
+nmtstp_wait_for_ip4_route (NMPlatform *platform, int ifindex, guint32 network, guint8 plen, guint32 metric, guint32 gateway, guint timeout_ms)
+{
+ return _wait_for_ip_route_until (platform, TRUE, ifindex, (NMIPAddr *) &network, plen, metric, (NMIPAddr *) &gateway, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms);
+}
+
+const NMPlatformIP4Route *
+nmtstp_wait_for_ip4_route_until (NMPlatform *platform, int ifindex, guint32 network, guint8 plen, guint32 metric, guint32 gateway, gint64 until_ms)
+{
+ return _wait_for_ip_route_until (platform, TRUE, ifindex, (NMIPAddr *) &network, plen, metric, (NMIPAddr *) &gateway, until_ms);
+}
+
+const NMPlatformIP6Route *
+nmtstp_wait_for_ip6_route (NMPlatform *platform, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric, const struct in6_addr *gateway, guint timeout_ms)
+{
+ return _wait_for_ip_route_until (platform, FALSE, ifindex, (NMIPAddr *) network, plen, metric, (NMIPAddr *) gateway, nm_utils_get_monotonic_timestamp_ms () + (gint64) timeout_ms);
+}
+
+const NMPlatformIP6Route *
+nmtstp_wait_for_ip6_route_until (NMPlatform *platform, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric, const struct in6_addr *gateway, gint64 until_ms)
+{
+ return _wait_for_ip_route_until (platform, FALSE, ifindex, (NMIPAddr *) network, plen, metric, (NMIPAddr *) gateway, until_ms);
+}
+
+/*****************************************************************************/
+
int
nmtstp_run_command_check_external_global (void)
{
@@ -903,6 +1021,152 @@ nmtstp_ip6_address_del (NMPlatform *platform,
/*****************************************************************************/
+static gconstpointer
+_ip_route_add (NMPlatform *platform,
+ gboolean external_command,
+ gboolean is_v4,
+ int ifindex,
+ NMIPConfigSource source,
+ const NMIPAddr *network,
+ guint8 plen,
+ const NMIPAddr *gateway,
+ guint32 *pref_src,
+ guint32 metric,
+ guint32 mss)
+{
+ gint64 end_time;
+ char s_network[NM_UTILS_INET_ADDRSTRLEN];
+ char s_gateway[NM_UTILS_INET_ADDRSTRLEN];
+ char s_pref_src[NM_UTILS_INET_ADDRSTRLEN];
+ const NMPlatformLink *pllink;
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ _init_platform (&platform, external_command);
+
+ pllink = nmtstp_link_get (platform, ifindex, NULL);
+ g_assert (pllink);
+
+ if (external_command) {
+ s_network[0] = '\0';
+ s_gateway[0] = '\0';
+ s_pref_src[0] = '\0';
+ if (is_v4) {
+ nm_utils_inet4_ntop (network->addr4, s_network);
+ if (gateway->addr4)
+ nm_utils_inet4_ntop (gateway->addr4, s_gateway);
+ if (*pref_src)
+ nm_utils_inet4_ntop (*pref_src, s_pref_src);
+ } else {
+ nm_utils_inet6_ntop (network ? &network->addr6 : &in6addr_any, s_network);
+ if (gateway && !IN6_IS_ADDR_UNSPECIFIED (&gateway->addr6))
+ nm_utils_inet6_ntop (&gateway->addr6, s_gateway);
+ g_assert (!pref_src);
+ }
+
+ nmtstp_run_command_check ("ip route append %s/%u%s dev '%s' metric %u protocol %d%s%s",
+ s_network,
+ plen,
+ s_gateway[0] ? nm_sprintf_bufa (100, " via %s", s_gateway) : "",
+ pllink->name,
+ metric,
+ nmp_utils_ip_config_source_coerce_to_rtprot (source),
+ s_pref_src[0] ? nm_sprintf_bufa (100, " src %s", s_pref_src) : "",
+ mss ? nm_sprintf_bufa (100, " advmss %u", mss) : "");
+ } else {
+ gboolean success;
+
+ if (is_v4) {
+ success = nm_platform_ip4_route_add (platform,
+ ifindex,
+ source,
+ network->addr4,
+ plen,
+ gateway->addr4,
+ *pref_src,
+ metric,
+ mss);
+ } else {
+ g_assert (pref_src == NULL);
+ success = nm_platform_ip6_route_add (platform,
+ ifindex,
+ source,
+ network ? network->addr6 : in6addr_any,
+ plen,
+ gateway ? gateway->addr6 : in6addr_any,
+ metric,
+ mss);
+ }
+ 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 (platform);
+
+ /* let's wait until we see the address as we added it. */
+ if (is_v4) {
+ const NMPlatformIP4Route *r;
+
+ r = nm_platform_ip4_route_get (platform, ifindex, network->addr4, plen, metric, gateway->addr4);
+ if (r) {
+ g_assert (r->ifindex == ifindex);
+ g_assert (r->network == network->addr4);
+ g_assert (r->plen == plen);
+ g_assert (r->metric == metric);
+ g_assert (r->gateway == gateway->addr4);
+ if ( r->mss == mss
+ && r->pref_src == *pref_src
+ && r->rt_source == nmp_utils_ip_config_source_round_trip_rtprot (source))
+ return r;
+ }
+ } else {
+ const NMPlatformIP6Route *r;
+
+ r = nm_platform_ip6_route_get (platform, ifindex, network ? network->addr6 : in6addr_any, plen, metric, gateway ? &gateway->addr6 : NULL);
+ if (r) {
+ g_assert (r->ifindex == ifindex);
+ g_assert (IN6_ARE_ADDR_EQUAL (&r->network, network ? &network->addr6 : &in6addr_any));
+ g_assert (r->plen == plen);
+ g_assert (r->metric == metric);
+ g_assert (IN6_ARE_ADDR_EQUAL (&r->gateway, gateway ? &gateway->addr6 : &in6addr_any));
+ if ( r->mss == mss
+ && r->rt_source == nmp_utils_ip_config_source_round_trip_rtprot (source))
+ return r;
+ }
+ }
+
+ /* for internal command, we expect not to reach this line.*/
+ g_assert (external_command);
+
+ nmtstp_assert_wait_for_signal_until (platform, end_time);
+ } while (TRUE);
+}
+
+const NMPlatformIP4Route *
+nmtstp_ip4_route_add (NMPlatform *platform, gboolean external_command,
+ int ifindex, NMIPConfigSource source,
+ guint32 network, guint8 plen,
+ guint32 gateway, guint32 pref_src,
+ guint32 metric, guint32 mss)
+{
+ return _ip_route_add (platform, external_command, TRUE, ifindex, source, (NMIPAddr *) &network, plen, (NMIPAddr *) &gateway, &pref_src, metric, mss);
+}
+
+const NMPlatformIP4Route *
+nmtstp_ip6_route_add (NMPlatform *platform, gboolean external_command,
+ int ifindex, NMIPConfigSource source,
+ const struct in6_addr *network, guint8 plen,
+ const struct in6_addr *gateway,
+ guint32 metric, guint32 mss)
+{
+ return _ip_route_add (platform, external_command, FALSE, ifindex, source, (NMIPAddr *) &network, plen, (NMIPAddr *) &gateway, NULL, metric, mss);
+}
+
+/*****************************************************************************/
+
#define _assert_pllink(platform, success, pllink, name, type) \
G_STMT_START { \
const NMPlatformLink *_pllink = (pllink); \