diff options
Diffstat (limited to 'src/platform/tests/test-common.c')
-rw-r--r-- | src/platform/tests/test-common.c | 294 |
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); \ |