diff options
Diffstat (limited to 'src/platform/tests/test-common.c')
| -rw-r--r-- | src/platform/tests/test-common.c | 2569 |
1 files changed, 0 insertions, 2569 deletions
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c deleted file mode 100644 index fb430046..00000000 --- a/src/platform/tests/test-common.c +++ /dev/null @@ -1,2569 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2016 - 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <sys/mount.h> -#include <sched.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <linux/if_tun.h> - -#include "test-common.h" - -#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)->received_count - -int NMTSTP_ENV1_IFINDEX = -1; -int NMTSTP_ENV1_EX = -1; - -/*****************************************************************************/ - -void -nmtstp_setup_platform(void) -{ - g_assert(_nmtstp_setup_platform_func); - _nmtstp_setup_platform_func(); -} - -gboolean -nmtstp_is_root_test(void) -{ - g_assert(_nmtstp_setup_platform_func); - return _nmtstp_setup_platform_func == nm_linux_platform_setup; -} - -gboolean -nmtstp_is_sysfs_writable(void) -{ - return !nmtstp_is_root_test() || (access("/sys/devices", W_OK) == 0); -} - -static void -_init_platform(NMPlatform **platform, gboolean external_command) -{ - g_assert(platform); - if (!*platform) - *platform = NM_PLATFORM_GET; - g_assert(NM_IS_PLATFORM(*platform)); - - if (external_command) - g_assert(NM_IS_LINUX_PLATFORM(*platform)); -} - -/*****************************************************************************/ - -static GArray * -_ipx_address_get_all(NMPlatform *self, int ifindex, NMPObjectType obj_type) -{ - NMPLookup lookup; - - g_assert(NM_IS_PLATFORM(self)); - g_assert(ifindex > 0); - g_assert(NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); - nmp_lookup_init_object(&lookup, obj_type, ifindex); - return nmp_cache_lookup_to_array(nm_platform_lookup(self, &lookup), - obj_type, - FALSE /*addresses are always visible. */); -} - -GArray * -nmtstp_platform_ip4_address_get_all(NMPlatform *self, int ifindex) -{ - return _ipx_address_get_all(self, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS); -} - -GArray * -nmtstp_platform_ip6_address_get_all(NMPlatform *self, int ifindex) -{ - return _ipx_address_get_all(self, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS); -} - -const NMPlatformIPAddress * -nmtstp_platform_ip_address_find(NMPlatform *self, int ifindex, int addr_family, gconstpointer addr) -{ - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); - const NMPlatformIPAddress *found = NULL; - NMDedupMultiIter iter; - const NMPObject * obj; - NMPLookup lookup; - - g_assert(NM_IS_PLATFORM(self)); - nm_assert(ifindex >= 0); - nm_assert_addr_family(addr_family); - nm_assert(addr); - - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); - nm_platform_iter_obj_for_each(&iter, self, &lookup, &obj) - { - const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS(obj); - - g_assert(NMP_OBJECT_GET_ADDR_FAMILY(obj) == addr_family); - g_assert(ifindex <= 0 || a->ifindex == ifindex); - - if (memcmp(addr, a->address_ptr, nm_utils_addr_family_to_size(addr_family)) != 0) - continue; - - g_assert(!found); - found = a; - } - - if (!IS_IPv4 && ifindex > 0) - g_assert(found - == (const NMPlatformIPAddress *) nm_platform_ip6_address_get(self, ifindex, addr)); - - return found; -} - -/*****************************************************************************/ - -typedef struct { - NMIPAddr addr; - int addr_family; - bool found : 1; -} IPAddressesAssertData; - -void -_nmtstp_platform_ip_addresses_assert(const char * filename, - int lineno, - NMPlatform * self, - int ifindex, - gboolean force_exact_4, - gboolean force_exact_6, - gboolean ignore_ll6, - guint addrs_len, - const char *const *addrs) -{ - gs_free IPAddressesAssertData *addrs_bin = NULL; - int IS_IPv4; - guint i; - - g_assert(filename); - g_assert(lineno >= 0); - g_assert(NM_IS_PLATFORM(self)); - g_assert(ifindex >= 0); - - addrs_bin = g_new(IPAddressesAssertData, addrs_len); - - for (i = 0; i < addrs_len; i++) { - const char *addrstr = addrs[i]; - int addr_family; - NMIPAddr a; - - if (!addrstr) { - addr_family = AF_UNSPEC; - a = nm_ip_addr_zero; - } else if (inet_pton(AF_INET, addrstr, &a) == 1) - addr_family = AF_INET; - else if (inet_pton(AF_INET6, addrstr, &a) == 1) - addr_family = AF_INET6; - else - g_error("%s:%d: invalid IP address in argument: %s", filename, lineno, addrstr); - - addrs_bin[i] = (IPAddressesAssertData){ - .addr_family = addr_family, - .addr = a, - .found = FALSE, - }; - } - - for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { - const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; - gs_unref_ptrarray GPtrArray *plat_addrs = NULL; - NMPLookup lookup; - guint j; - - plat_addrs = nm_platform_lookup_clone( - self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex), - NULL, - NULL); - - for (i = 0; i < addrs_len; i++) { - IPAddressesAssertData *addr_bin = &addrs_bin[i]; - - if (addr_bin->addr_family != addr_family) - continue; - - g_assert(!addr_bin->found); - for (j = 0; j < nm_g_ptr_array_len(plat_addrs);) { - const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS(plat_addrs->pdata[j]); - - if (memcmp(&addr_bin->addr, - a->address_ptr, - nm_utils_addr_family_to_size(addr_family)) - != 0) { - j++; - continue; - } - - g_assert(!addr_bin->found); - addr_bin->found = TRUE; - g_ptr_array_remove_index_fast(plat_addrs, j); - } - - if (!addr_bin->found) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - g_error("%s:%d: IPv%c address %s was not found on ifindex %d", - filename, - lineno, - nm_utils_addr_family_to_char(addr_bin->addr_family), - nm_utils_inet_ntop(addr_bin->addr_family, &addr_bin->addr, sbuf), - ifindex); - } - } - if (!IS_IPv4 && ignore_ll6 && nm_g_ptr_array_len(plat_addrs) > 0) { - /* we prune all remaining, non-matching IPv6 link local addresses. */ - for (j = 0; j < nm_g_ptr_array_len(plat_addrs);) { - const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS(plat_addrs->pdata[j]); - - if (!IN6_IS_ADDR_LINKLOCAL(a->address_ptr)) { - j++; - continue; - } - - g_ptr_array_remove_index_fast(plat_addrs, j); - } - } - if ((IS_IPv4 ? force_exact_4 : force_exact_6) && nm_g_ptr_array_len(plat_addrs) > 0) { - char sbuf[sizeof(_nm_utils_to_string_buffer)]; - - g_error("%s:%d: %u IPv%c addresses found on ifindex %d that should not be there (one " - "is %s)", - filename, - lineno, - plat_addrs->len, - nm_utils_addr_family_to_char(addr_family), - ifindex, - nmp_object_to_string(plat_addrs->pdata[0], - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf, - sizeof(sbuf))); - } - } -} - -/*****************************************************************************/ - -gboolean -nmtstp_platform_ip4_route_delete(NMPlatform *platform, - int ifindex, - in_addr_t network, - guint8 plen, - guint32 metric) -{ - NMDedupMultiIter iter; - - nm_platform_process_events(platform); - - nm_dedup_multi_iter_for_each ( - &iter, - nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex)) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(iter.current->obj); - - if (r->ifindex != ifindex || r->network != network || r->plen != plen - || r->metric != metric) { - continue; - } - - return nm_platform_object_delete(platform, NMP_OBJECT_UP_CAST(r)); - } - - return TRUE; -} - -gboolean -nmtstp_platform_ip6_route_delete(NMPlatform * platform, - int ifindex, - struct in6_addr network, - guint8 plen, - guint32 metric) -{ - NMDedupMultiIter iter; - - nm_platform_process_events(platform); - - nm_dedup_multi_iter_for_each ( - &iter, - nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex)) { - const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE(iter.current->obj); - - if (r->ifindex != ifindex || !IN6_ARE_ADDR_EQUAL(&r->network, &network) || r->plen != plen - || r->metric != metric) { - continue; - } - - return nm_platform_object_delete(platform, NMP_OBJECT_UP_CAST(r)); - } - - return TRUE; -} - -/*****************************************************************************/ - -SignalData * -add_signal_full(const char * name, - NMPlatformSignalChangeType change_type, - GCallback callback, - int ifindex, - const char * ifname) -{ - SignalData *data = g_new0(SignalData, 1); - - data->name = name; - data->change_type = change_type; - data->received_count = 0; - data->handler_id = g_signal_connect(NM_PLATFORM_GET, name, callback, data); - data->ifindex = ifindex; - data->ifname = ifname; - - g_assert(data->handler_id > 0); - - return data; -} - -void -_accept_signal(const char *file, int line, const char *func, SignalData *data) -{ - _LOGD("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal one time: " SIGNAL_DATA_FMT, - file, - line, - func, - SIGNAL_DATA_ARG(data)); - if (data->received_count != 1) - g_error("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal one " - "time: " SIGNAL_DATA_FMT, - file, - line, - func, - SIGNAL_DATA_ARG(data)); - data->received_count = 0; -} - -void -_accept_signals(const char *file, int line, const char *func, SignalData *data, int min, int max) -{ - _LOGD("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal [%d,%d] times: " SIGNAL_DATA_FMT, - file, - line, - func, - min, - max, - SIGNAL_DATA_ARG(data)); - if (data->received_count < min || data->received_count > max) - g_error("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal [%d,%d] " - "times: " SIGNAL_DATA_FMT, - file, - line, - func, - min, - max, - SIGNAL_DATA_ARG(data)); - data->received_count = 0; -} - -void -_ensure_no_signal(const char *file, int line, const char *func, SignalData *data) -{ - _LOGD("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal 0 times: " SIGNAL_DATA_FMT, - file, - line, - func, - SIGNAL_DATA_ARG(data)); - if (data->received_count > 0) - 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); - nm_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)); - if (data->received_count) - g_error("NMPlatformSignalAssert: %s:%d, %s(): failure to wait for signal: " SIGNAL_DATA_FMT, - file, - line, - func, - SIGNAL_DATA_ARG(data)); - - data->loop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(data->loop); - nm_clear_pointer(&data->loop, g_main_loop_unref); - - _accept_signal(file, line, func, data); -} - -void -_free_signal(const char *file, int line, const char *func, SignalData *data) -{ - _LOGD("NMPlatformSignalAssert: %s:%d, %s(): free signal: " SIGNAL_DATA_FMT, - file, - line, - func, - SIGNAL_DATA_ARG(data)); - if (data->received_count != 0) - g_error("NMPlatformSignalAssert: %s:%d, %s(): failure to free non-accepted " - "signal: " SIGNAL_DATA_FMT, - file, - line, - func, - SIGNAL_DATA_ARG(data)); - - g_signal_handler_disconnect(NM_PLATFORM_GET, data->handler_id); - g_free(data); -} - -void -link_callback(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *received, - int change_type_i, - SignalData * data) -{ - const NMPObjectType obj_type = obj_type_i; - const NMPlatformSignalChangeType change_type = change_type_i; - NMPLookup lookup; - NMDedupMultiIter iter; - const NMPlatformLink * cached; - - g_assert_cmpint(obj_type, ==, NMP_OBJECT_TYPE_LINK); - g_assert(received); - g_assert_cmpint(received->ifindex, ==, ifindex); - g_assert(data && data->name); - g_assert_cmpstr(data->name, ==, NM_PLATFORM_SIGNAL_LINK_CHANGED); - - if (data->ifindex && data->ifindex != received->ifindex) - return; - if (data->ifname - && g_strcmp0(data->ifname, nm_platform_link_get_name(NM_PLATFORM_GET, ifindex)) != 0) - return; - if (change_type != data->change_type) - return; - - if (data->loop) { - _LOGD("Quitting main loop."); - g_main_loop_quit(data->loop); - } - - data->received_count++; - _LOGD("Received signal '%s-%s' ifindex %d ifname '%s' %dth time.", - data->name, - nm_platform_signal_change_type_to_string(data->change_type), - ifindex, - received->name, - data->received_count); - - if (change_type == NM_PLATFORM_SIGNAL_REMOVED) - g_assert(!nm_platform_link_get_name(NM_PLATFORM_GET, ifindex)); - else - g_assert(nm_platform_link_get_name(NM_PLATFORM_GET, ifindex)); - - /* Check the data */ - g_assert(received->ifindex > 0); - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_LINK); - nmp_cache_iter_for_each_link (&iter, nm_platform_lookup(platform, &lookup), &cached) { - if (!nmp_object_is_visible(NMP_OBJECT_UP_CAST(cached))) - continue; - if (cached->ifindex == received->ifindex) { - g_assert_cmpint(nm_platform_link_cmp(cached, received), ==, 0); - g_assert(!memcmp(cached, received, sizeof(*cached))); - if (data->change_type == NM_PLATFORM_SIGNAL_REMOVED) - g_error("Deleted link still found in the local cache."); - return; - } - } - - if (data->change_type != NM_PLATFORM_SIGNAL_REMOVED) - g_error("Added/changed link not found in the local cache."); -} - -/*****************************************************************************/ - -static const NMPlatformIP4Route * -_ip4_route_get(NMPlatform *platform, - int ifindex, - guint32 network, - int plen, - guint32 metric, - guint8 tos, - guint * out_c_exists) -{ - NMDedupMultiIter iter; - NMPLookup lookup; - const NMPObject * o = NULL; - guint c; - const NMPlatformIP4Route *r = NULL; - - _init_platform(&platform, FALSE); - - nmp_lookup_init_ip4_route_by_weak_id(&lookup, network, plen, metric, tos); - - c = 0; - nmp_cache_iter_for_each (&iter, nm_platform_lookup(platform, &lookup), &o) { - if (NMP_OBJECT_CAST_IP4_ROUTE(o)->ifindex != ifindex && ifindex > 0) - continue; - if (!r) - r = NMP_OBJECT_CAST_IP4_ROUTE(o); - c++; - } - - NM_SET_OUT(out_c_exists, c); - return r; -} - -const NMPlatformIP4Route * -_nmtstp_assert_ip4_route_exists(const char *file, - guint line, - const char *func, - NMPlatform *platform, - int c_exists, - const char *ifname, - guint32 network, - int plen, - guint32 metric, - guint8 tos) -{ - int ifindex; - guint c; - const NMPlatformIP4Route *r = NULL; - - _init_platform(&platform, FALSE); - - ifindex = -1; - if (ifname) { - ifindex = nm_platform_link_get_ifindex(platform, ifname); - g_assert(ifindex > 0); - } - - r = _ip4_route_get(platform, ifindex, network, plen, metric, tos, &c); - - if (c != c_exists && c_exists != -1) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - g_error("[%s:%u] %s(): The ip4 route %s/%d metric %u tos %u shall exist %u times, but " - "platform has it %u times", - file, - line, - func, - _nm_utils_inet4_ntop(network, sbuf), - plen, - metric, - tos, - c_exists, - c); - } - - return r; -} - -const NMPlatformIP4Route * -nmtstp_ip4_route_get(NMPlatform *platform, - int ifindex, - guint32 network, - int plen, - guint32 metric, - guint8 tos) -{ - return _ip4_route_get(platform, ifindex, network, plen, metric, tos, NULL); -} - -/*****************************************************************************/ - -static const NMPlatformIP6Route * -_ip6_route_get(NMPlatform * platform, - int ifindex, - const struct in6_addr *network, - guint plen, - guint32 metric, - const struct in6_addr *src, - guint8 src_plen, - guint * out_c_exists) -{ - NMDedupMultiIter iter; - NMPLookup lookup; - const NMPObject * o = NULL; - guint c; - const NMPlatformIP6Route *r = NULL; - - _init_platform(&platform, FALSE); - - nmp_lookup_init_ip6_route_by_weak_id(&lookup, network, plen, metric, src, src_plen); - - c = 0; - nmp_cache_iter_for_each (&iter, nm_platform_lookup(platform, &lookup), &o) { - if (NMP_OBJECT_CAST_IP6_ROUTE(o)->ifindex != ifindex && ifindex > 0) - continue; - if (!r) - r = NMP_OBJECT_CAST_IP6_ROUTE(o); - c++; - } - - NM_SET_OUT(out_c_exists, c); - return r; -} - -const NMPlatformIP6Route * -_nmtstp_assert_ip6_route_exists(const char * file, - guint line, - const char * func, - NMPlatform * platform, - int c_exists, - const char * ifname, - const struct in6_addr *network, - guint plen, - guint32 metric, - const struct in6_addr *src, - guint8 src_plen) -{ - int ifindex; - guint c; - const NMPlatformIP6Route *r = NULL; - - _init_platform(&platform, FALSE); - - ifindex = -1; - if (ifname) { - ifindex = nm_platform_link_get_ifindex(platform, ifname); - g_assert(ifindex > 0); - } - - r = _ip6_route_get(platform, ifindex, network, plen, metric, src, src_plen, &c); - - if (c != c_exists && c_exists != -1) { - char s_src[NM_UTILS_INET_ADDRSTRLEN]; - char s_network[NM_UTILS_INET_ADDRSTRLEN]; - - g_error("[%s:%u] %s(): The ip6 route %s/%d metric %u src %s/%d shall exist %u times, but " - "platform has it %u times", - file, - line, - func, - _nm_utils_inet6_ntop(network, s_network), - plen, - metric, - _nm_utils_inet6_ntop(src, s_src), - src_plen, - c_exists, - c); - } - - return r; -} - -const NMPlatformIP6Route * -nmtstp_ip6_route_get(NMPlatform * platform, - int ifindex, - const struct in6_addr *network, - guint plen, - guint32 metric, - const struct in6_addr *src, - guint8 src_plen) -{ - return _ip6_route_get(platform, ifindex, network, plen, metric, src, src_plen, NULL); -} - -/*****************************************************************************/ - -int -nmtstp_run_command(const char *format, ...) -{ - 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); - result = system(command); - _LOGD("Command finished: result=%d", result); - - return result; -} - -/*****************************************************************************/ - -typedef struct { - GMainLoop *loop; - guint signal_counts; - guint id; -} WaitForSignalData; - -static void -_wait_for_signal_cb(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *plink, - int change_type_i, - gpointer user_data) -{ - WaitForSignalData *data = user_data; - - data->signal_counts++; - nm_clear_g_source(&data->id); - g_main_loop_quit(data->loop); -} - -static gboolean -_wait_for_signal_timeout(gpointer user_data) -{ - WaitForSignalData *data = user_data; - - g_assert(data->id); - data->id = 0; - g_main_loop_quit(data->loop); - return G_SOURCE_REMOVE; -} - -guint -nmtstp_wait_for_signal(NMPlatform *platform, gint64 timeout_msec) -{ - WaitForSignalData data = {0}; - gulong id_link, id_ip4_address, id_ip6_address, id_ip4_route, id_ip6_route; - gulong id_qdisc, id_tfilter; - - _init_platform(&platform, FALSE); - - data.loop = g_main_loop_new(NULL, FALSE); - - id_link = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - id_ip4_address = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - id_ip6_address = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - id_ip4_route = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - id_ip6_route = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - id_qdisc = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_QDISC_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - id_tfilter = g_signal_connect(platform, - NM_PLATFORM_SIGNAL_TFILTER_CHANGED, - G_CALLBACK(_wait_for_signal_cb), - &data); - - /* if timeout_msec is negative, it means the wait-time already expired. - * Maybe, we should do nothing and return right away, without even - * processing events from platform. However, that inconsistency (of not - * processing events from mainloop) is inconvenient. - * - * It's better that on the return of nmtstp_wait_for_signal(), we always - * have no events pending. So, a negative timeout is treated the same as - * a zero timeout: we check whether there are any events pending in platform, - * and quite the mainloop immediately afterwards. But we always check. */ - - data.id = g_timeout_add(CLAMP(timeout_msec, 0, G_MAXUINT32), _wait_for_signal_timeout, &data); - - g_main_loop_run(data.loop); - - g_assert(!data.id); - g_assert(nm_clear_g_signal_handler(platform, &id_link)); - g_assert(nm_clear_g_signal_handler(platform, &id_ip4_address)); - g_assert(nm_clear_g_signal_handler(platform, &id_ip6_address)); - g_assert(nm_clear_g_signal_handler(platform, &id_ip4_route)); - g_assert(nm_clear_g_signal_handler(platform, &id_ip6_route)); - g_assert(nm_clear_g_signal_handler(platform, &id_tfilter)); - g_assert(nm_clear_g_signal_handler(platform, &id_qdisc)); - - nm_clear_pointer(&data.loop, g_main_loop_unref); - - /* return the number of signals, or 0 if timeout was reached .*/ - return data.signal_counts; -} - -guint -nmtstp_wait_for_signal_until(NMPlatform *platform, gint64 until_ms) -{ - gint64 now; - guint signal_counts; - - while (TRUE) { - now = nm_utils_get_monotonic_timestamp_msec(); - - if (until_ms < now) - return 0; - - signal_counts = nmtstp_wait_for_signal(platform, until_ms - now); - if (signal_counts) - return signal_counts; - } -} - -const NMPlatformLink * -nmtstp_wait_for_link(NMPlatform *platform, - const char *ifname, - NMLinkType expected_link_type, - gint64 timeout_msec) -{ - return nmtstp_wait_for_link_until( - platform, - ifname, - expected_link_type, - timeout_msec ? nm_utils_get_monotonic_timestamp_msec() + timeout_msec : 0); -} - -const NMPlatformLink * -nmtstp_wait_for_link_until(NMPlatform *platform, - const char *ifname, - NMLinkType expected_link_type, - gint64 until_ms) -{ - const NMPlatformLink *plink; - gint64 now; - gboolean waited_once = FALSE; - - _init_platform(&platform, FALSE); - - while (TRUE) { - now = nm_utils_get_monotonic_timestamp_msec(); - - plink = nm_platform_link_get_by_ifname(platform, ifname); - if (plink && (expected_link_type == NM_LINK_TYPE_NONE || plink->type == expected_link_type)) - return plink; - - if (until_ms == 0) { - /* don't wait, don't even poll the socket. */ - return NULL; - } - - if (waited_once && until_ms < now) { - /* timeout reached (+ we already waited for a signal at least once). */ - return NULL; - } - - waited_once = TRUE; - /* regardless of whether timeout is already reached, we poll the netlink - * socket a bit. */ - nmtstp_wait_for_signal(platform, until_ms - now); - } -} - -/*****************************************************************************/ - -int -nmtstp_run_command_check_external_global(void) -{ - if (!nmtstp_is_root_test()) - return FALSE; - switch (nmtst_get_rand_uint32() % 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_uint32() % 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_sec(); - g_assert(now > 0); - - g_assert(expected_preferred <= expected_lifetime); - - if (expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && expected_preferred == 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 (((gint64) adr) - offset <= ((gint64) lft) - CHECK_LIFETIME_MAX_DIFF - || ((gint64) adr) - offset >= ((gint64) 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_sec(); - g_assert(now > 0); - - g_assert(expected_preferred <= expected_lifetime); - - if (expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && expected_preferred == 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 - 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(NMPlatform * platform, - gboolean external_command, - gboolean is_v4, - int ifindex, - const NMIPAddr *address, - int plen, - const NMIPAddr *peer_address, - guint32 lifetime, - guint32 preferred, - guint32 flags, - const char * label) -{ - gint64 end_time; - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, 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]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - - ifname = nm_platform_link_get_name(platform, ifindex); - g_assert(ifname); - - 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) { - char s_peer[NM_UTILS_INET_ADDRSTRLEN + 50]; - - g_assert(flags == 0); - - if (peer_address->addr4 != address->addr4 || nmtst_get_rand_uint32() % 2) { - /* If the peer is the same as the local address, we can omit it. The result should be identical */ - nm_sprintf_buf(s_peer, " peer %s", _nm_utils_inet4_ntop(peer_address->addr4, b2)); - } else - s_peer[0] = '\0'; - - nmtstp_run_command_check("ip address change %s%s/%d dev %s%s%s%s", - _nm_utils_inet4_ntop(address->addr4, b1), - s_peer, - 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) { - success = nm_platform_ip4_address_add(platform, - ifindex, - address->addr4, - plen, - peer_address->addr4, - 0u, - lifetime, - preferred, - flags, - label); - } else { - g_assert(label == NULL); - success = nm_platform_ip6_address_add(platform, - 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_msec() + 500; - 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 NMPlatformIP4Address *a; - - g_assert(flags == 0); - a = nm_platform_ip4_address_get(platform, - ifindex, - address->addr4, - plen, - peer_address->addr4); - if (a && a->peer_address == peer_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(platform, ifindex, &address->addr6); - 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); - - nmtstp_assert_wait_for_signal_until(platform, end_time); - } while (TRUE); -} - -void -nmtstp_ip4_address_add(NMPlatform *platform, - gboolean external_command, - int ifindex, - in_addr_t address, - int plen, - in_addr_t peer_address, - guint32 lifetime, - guint32 preferred, - guint32 flags, - const char *label) -{ - _ip_address_add(platform, - external_command, - TRUE, - ifindex, - (NMIPAddr *) &address, - plen, - (NMIPAddr *) &peer_address, - lifetime, - preferred, - flags, - label); -} - -void -nmtstp_ip6_address_add(NMPlatform * platform, - gboolean external_command, - int ifindex, - struct in6_addr address, - int plen, - struct in6_addr peer_address, - guint32 lifetime, - guint32 preferred, - guint32 flags) -{ - _ip_address_add(platform, - external_command, - FALSE, - ifindex, - (NMIPAddr *) &address, - plen, - (NMIPAddr *) &peer_address, - lifetime, - preferred, - flags, - NULL); -} - -void -nmtstp_ip4_route_add(NMPlatform * platform, - int ifindex, - NMIPConfigSource source, - in_addr_t network, - guint8 plen, - in_addr_t gateway, - in_addr_t pref_src, - guint32 metric, - guint32 mss) -{ - NMPlatformIP4Route route = {}; - - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.pref_src = pref_src; - route.metric = metric; - route.mss = mss; - - g_assert( - NMTST_NM_ERR_SUCCESS(nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_REPLACE, &route))); -} - -void -nmtstp_ip6_route_add(NMPlatform * platform, - int ifindex, - NMIPConfigSource source, - struct in6_addr network, - guint8 plen, - struct in6_addr gateway, - struct in6_addr pref_src, - guint32 metric, - guint32 mss) -{ - NMPlatformIP6Route route = {}; - - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.pref_src = pref_src; - route.metric = metric; - route.mss = mss; - - g_assert( - NMTST_NM_ERR_SUCCESS(nm_platform_ip6_route_add(platform, NMP_NLM_FLAG_REPLACE, &route))); -} - -/*****************************************************************************/ - -static void -_ip_address_del(NMPlatform * platform, - gboolean external_command, - gboolean is_v4, - int ifindex, - const NMIPAddr *address, - int plen, - const NMIPAddr *peer_address) -{ - gint64 end_time; - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - const char *ifname; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - int success; - gboolean had_address; - - ifname = nm_platform_link_get_name(platform, ifindex); - g_assert(ifname); - - /* let's wait until we see the address as we added it. */ - if (is_v4) - had_address = !!nm_platform_ip4_address_get(platform, - ifindex, - address->addr4, - plen, - peer_address->addr4); - else - had_address = !!nm_platform_ip6_address_get(platform, ifindex, &address->addr6); - - 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 != address->addr4 ? " peer " : "", - peer_address->addr4 != 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(platform, - ifindex, - address->addr4, - plen, - peer_address->addr4); - } else { - g_assert(!peer_address); - success = nm_platform_ip6_address_delete(platform, ifindex, address->addr6, plen); - } - g_assert(success); - } - - /* Let's wait until we get the result */ - end_time = nm_utils_get_monotonic_timestamp_msec() + 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 NMPlatformIP4Address *a; - - a = nm_platform_ip4_address_get(platform, - ifindex, - address->addr4, - plen, - peer_address->addr4); - if (!a) - break; - } else { - const NMPlatformIP6Address *a; - - a = nm_platform_ip6_address_get(platform, ifindex, &address->addr6); - if (!a) - break; - } - - /* 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); -} - -void -nmtstp_ip4_address_del(NMPlatform *platform, - gboolean external_command, - int ifindex, - in_addr_t address, - int plen, - in_addr_t peer_address) -{ - _ip_address_del(platform, - external_command, - TRUE, - ifindex, - (NMIPAddr *) &address, - plen, - (NMIPAddr *) &peer_address); -} - -void -nmtstp_ip6_address_del(NMPlatform * platform, - gboolean external_command, - int ifindex, - struct in6_addr address, - int plen) -{ - _ip_address_del(platform, external_command, FALSE, ifindex, (NMIPAddr *) &address, plen, NULL); -} - -/*****************************************************************************/ - -#define _assert_pllink(platform, success, pllink, name, type) \ - G_STMT_START \ - { \ - const NMPlatformLink *_pllink = (pllink); \ - \ - if ((success)) { \ - g_assert(_pllink); \ - g_assert(_pllink \ - == nmtstp_link_get_typed(platform, _pllink->ifindex, (name), (type))); \ - } else { \ - g_assert(!_pllink); \ - g_assert(!nmtstp_link_get(platform, 0, (name))); \ - } \ - } \ - G_STMT_END - -const NMPlatformLink * -nmtstp_link_bridge_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkBridge *lnk) -{ - const NMPlatformLink * pllink = NULL; - const NMPlatformLnkBridge *ll = NULL; - int r = 0; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - char sbuf_gfw[100]; - char sbuf_mhm[100]; - char sbuf_mlmc[100]; - char sbuf_mlmi[100]; - char sbuf_mmi[100]; - char sbuf_mqi[100]; - char sbuf_mqii[100]; - char sbuf_msqc[100]; - char sbuf_msqi[100]; - char sbuf_mqri[100]; - - r = nmtstp_run_command( - "ip link add %s type bridge " - "forward_delay %u " - "hello_time %u " - "max_age %u " - "ageing_time %u " - "stp_state %d " - "priority %u " - "vlan_protocol %u " - "vlan_stats_enabled %d " - "%s" /* group_fwd_mask */ - "group_address " NM_ETHER_ADDR_FORMAT_STR " " - "mcast_snooping %d " - "mcast_router %u " - "mcast_query_use_ifaddr %d " - "mcast_querier %d " - "%s" /* mcast_hash_max */ - "%s" /* mcast_last_member_count */ - "%s" /* mcast_startup_query_count */ - "%s" /* mcast_last_member_interval */ - "%s" /* mcast_membership_interval */ - "%s" /* mcast_querier_interval */ - "%s" /* mcast_query_interval */ - "%s" /* mcast_query_response_interval */ - "%s" /* mcast_startup_query_interval */ - "", - name, - lnk->forward_delay, - lnk->hello_time, - lnk->max_age, - lnk->ageing_time, - (int) lnk->stp_state, - lnk->priority, - lnk->vlan_protocol, - (int) lnk->vlan_stats_enabled, - lnk->group_fwd_mask != 0 - ? nm_sprintf_buf(sbuf_gfw, "group_fwd_mask %#x ", lnk->group_fwd_mask) - : "", - NM_ETHER_ADDR_FORMAT_VAL(lnk->group_addr), - (int) lnk->mcast_snooping, - lnk->mcast_router, - (int) lnk->mcast_query_use_ifaddr, - (int) lnk->mcast_querier, - lnk->mcast_hash_max != NM_BRIDGE_MULTICAST_HASH_MAX_DEF - ? nm_sprintf_buf(sbuf_mhm, "mcast_hash_max %u ", lnk->mcast_hash_max) - : "", - lnk->mcast_last_member_count != NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF - ? nm_sprintf_buf(sbuf_mlmc, - "mcast_last_member_count %u ", - lnk->mcast_last_member_count) - : "", - lnk->mcast_startup_query_count != NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF - ? nm_sprintf_buf(sbuf_msqc, - "mcast_startup_query_count %u ", - lnk->mcast_startup_query_count) - : "", - lnk->mcast_last_member_interval != NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF - ? nm_sprintf_buf(sbuf_mlmi, - "mcast_last_member_interval %" G_GUINT64_FORMAT " ", - lnk->mcast_last_member_interval) - : "", - lnk->mcast_membership_interval != NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF - ? nm_sprintf_buf(sbuf_mmi, - "mcast_membership_interval %" G_GUINT64_FORMAT " ", - lnk->mcast_membership_interval) - : "", - lnk->mcast_querier_interval != NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF - ? nm_sprintf_buf(sbuf_mqi, - "mcast_querier_interval %" G_GUINT64_FORMAT " ", - lnk->mcast_querier_interval) - : "", - lnk->mcast_query_interval != NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF - ? nm_sprintf_buf(sbuf_mqii, - "mcast_query_interval %" G_GUINT64_FORMAT " ", - lnk->mcast_query_interval) - : "", - lnk->mcast_query_response_interval != NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF - ? nm_sprintf_buf(sbuf_mqri, - "mcast_query_response_interval %" G_GUINT64_FORMAT " ", - lnk->mcast_query_response_interval) - : "", - lnk->mcast_startup_query_interval != NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF - ? nm_sprintf_buf(sbuf_msqi, - "mcast_startup_query_interval %" G_GUINT64_FORMAT " ", - lnk->mcast_startup_query_interval) - : ""); - if (r == 0) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_BRIDGE, 100); - else - _LOGI( - "Adding bridge device via iproute2 failed. Assume iproute2 is not up to the task."); - } - - if (!pllink) { - r = nm_platform_link_bridge_add(platform, name, NULL, 0, 0, lnk, &pllink); - } - - _assert_pllink(platform, r == 0, pllink, name, NM_LINK_TYPE_BRIDGE); - - ll = NMP_OBJECT_CAST_LNK_BRIDGE(NMP_OBJECT_UP_CAST(pllink)->_link.netlink.lnk); - - g_assert_cmpint(lnk->forward_delay, ==, ll->forward_delay); - g_assert_cmpint(lnk->hello_time, ==, ll->hello_time); - g_assert_cmpint(lnk->max_age, ==, ll->max_age); - g_assert_cmpint(lnk->ageing_time, ==, ll->ageing_time); - g_assert_cmpint(lnk->stp_state, ==, ll->stp_state); - g_assert_cmpint(lnk->priority, ==, ll->priority); - g_assert_cmpint(lnk->vlan_stats_enabled, ==, ll->vlan_stats_enabled); - g_assert_cmpint(lnk->group_fwd_mask, ==, ll->group_fwd_mask); - g_assert_cmpint(lnk->mcast_snooping, ==, ll->mcast_snooping); - g_assert_cmpint(lnk->mcast_router, ==, ll->mcast_router); - g_assert_cmpint(lnk->mcast_query_use_ifaddr, ==, ll->mcast_query_use_ifaddr); - g_assert_cmpint(lnk->mcast_querier, ==, ll->mcast_querier); - g_assert_cmpint(lnk->mcast_hash_max, ==, ll->mcast_hash_max); - g_assert_cmpint(lnk->mcast_last_member_count, ==, ll->mcast_last_member_count); - g_assert_cmpint(lnk->mcast_startup_query_count, ==, ll->mcast_startup_query_count); - g_assert_cmpint(lnk->mcast_last_member_interval, ==, ll->mcast_last_member_interval); - g_assert_cmpint(lnk->mcast_membership_interval, ==, ll->mcast_membership_interval); - g_assert_cmpint(lnk->mcast_querier_interval, ==, ll->mcast_querier_interval); - g_assert_cmpint(lnk->mcast_query_interval, ==, ll->mcast_query_interval); - g_assert_cmpint(lnk->mcast_query_response_interval, ==, ll->mcast_query_response_interval); - g_assert_cmpint(lnk->mcast_startup_query_interval, ==, ll->mcast_startup_query_interval); - - return pllink; -} -const NMPlatformLink * -nmtstp_link_veth_add(NMPlatform *platform, - gboolean external_command, - const char *name, - const char *peer) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - success = !nmtstp_run_command("ip link add dev %s type veth peer name %s", name, peer); - if (success) { - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VETH, 100); - nmtstp_assert_wait_for_link(platform, peer, NM_LINK_TYPE_VETH, 10); - } - } else - success = NMTST_NM_ERR_SUCCESS(nm_platform_link_veth_add(platform, name, peer, &pllink)); - - g_assert(success); - _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_VETH); - return pllink; -} - -const NMPlatformLink * -nmtstp_link_dummy_add(NMPlatform *platform, gboolean external_command, const char *name) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - success = !nmtstp_run_command("ip link add %s type dummy", name); - if (success) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_DUMMY, 100); - } else - success = NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add(platform, name, &pllink)); - - g_assert(success); - _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_DUMMY); - return pllink; -} - -const NMPlatformLink * -nmtstp_link_gre_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkGre *lnk) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - char b1[INET_ADDRSTRLEN]; - char b2[INET_ADDRSTRLEN]; - NMLinkType link_type; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - link_type = lnk->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE; - - _init_platform(&platform, external_command); - - if (external_command) { - gs_free char *dev = NULL; - char * obj, *type; - - if (lnk->parent_ifindex) - dev = - g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); - - obj = lnk->is_tap ? "link" : "tunnel"; - type = lnk->is_tap ? "type gretap" : "mode gre"; - - success = !nmtstp_run_command("ip %s add %s %s %s local %s remote %s ttl %u tos %02x %s", - obj, - name, - type, - dev ?: "", - _nm_utils_inet4_ntop(lnk->local, b1), - _nm_utils_inet4_ntop(lnk->remote, b2), - lnk->ttl, - lnk->tos, - lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); - if (success) - pllink = nmtstp_assert_wait_for_link(platform, name, link_type, 100); - } else - success = - NMTST_NM_ERR_SUCCESS(nm_platform_link_gre_add(platform, name, NULL, 0, lnk, &pllink)); - - _assert_pllink(platform, success, pllink, name, link_type); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_ip6tnl_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkIp6Tnl *lnk) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - char encap[20]; - char tclass[20]; - gboolean encap_ignore; - gboolean tclass_inherit; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - g_assert(!lnk->is_gre); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - gs_free char *dev = NULL; - const char * mode; - - if (lnk->parent_ifindex) - dev = - g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); - - switch (lnk->proto) { - case IPPROTO_IPIP: - mode = "ipip6"; - break; - case IPPROTO_IPV6: - mode = "ip6ip6"; - break; - default: - g_assert_not_reached(); - } - - encap_ignore = NM_FLAGS_HAS(lnk->flags, IP6_TNL_F_IGN_ENCAP_LIMIT); - tclass_inherit = NM_FLAGS_HAS(lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); - - success = !nmtstp_run_command( - "ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %s encaplimit %s " - "flowlabel %x", - name, - mode, - dev, - _nm_utils_inet6_ntop(&lnk->local, b1), - _nm_utils_inet6_ntop(&lnk->remote, b2), - lnk->ttl, - tclass_inherit ? "inherit" : nm_sprintf_buf(tclass, "%02x", lnk->tclass), - encap_ignore ? "none" : nm_sprintf_buf(encap, "%u", lnk->encap_limit), - lnk->flow_label); - if (success) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_IP6TNL, 100); - } else - success = NMTST_NM_ERR_SUCCESS(nm_platform_link_ip6tnl_add(platform, name, lnk, &pllink)); - - _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_IP6TNL); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_ip6gre_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkIp6Tnl *lnk) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - char tclass[20]; - gboolean tclass_inherit; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - g_assert(lnk->is_gre); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - gs_free char *dev = NULL; - - if (lnk->parent_ifindex) - dev = - g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); - - tclass_inherit = NM_FLAGS_HAS(lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); - - success = !nmtstp_run_command( - "ip link add %s type %s %s local %s remote %s ttl %u tclass %s flowlabel %x", - name, - lnk->is_tap ? "ip6gretap" : "ip6gre", - dev, - _nm_utils_inet6_ntop(&lnk->local, b1), - _nm_utils_inet6_ntop(&lnk->remote, b2), - lnk->ttl, - tclass_inherit ? "inherit" : nm_sprintf_buf(tclass, "%02x", lnk->tclass), - lnk->flow_label); - if (success) { - pllink = nmtstp_assert_wait_for_link(platform, - name, - lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP - : NM_LINK_TYPE_IP6GRE, - 100); - } - } else - success = NMTST_NM_ERR_SUCCESS( - nm_platform_link_ip6gre_add(platform, name, NULL, 0, lnk, &pllink)); - - _assert_pllink(platform, - success, - pllink, - name, - lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_ipip_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkIpIp *lnk) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - char b1[INET_ADDRSTRLEN]; - char b2[INET_ADDRSTRLEN]; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - gs_free char *dev = NULL; - - if (lnk->parent_ifindex) - dev = - g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); - - success = !nmtstp_run_command( - "ip tunnel add %s mode ipip %s local %s remote %s ttl %u tos %02x %s", - name, - dev, - _nm_utils_inet4_ntop(lnk->local, b1), - _nm_utils_inet4_ntop(lnk->remote, b2), - lnk->ttl, - lnk->tos, - lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); - if (success) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_IPIP, 100); - } else - success = NMTST_NM_ERR_SUCCESS(nm_platform_link_ipip_add(platform, name, lnk, &pllink)); - - _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_IPIP); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_macvlan_add(NMPlatform * platform, - gboolean external_command, - const char * name, - int parent, - const NMPlatformLnkMacvlan *lnk) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - NMLinkType link_type; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - link_type = lnk->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN; - - if (external_command) { - const char *dev; - char * modes[] = { - [MACVLAN_MODE_BRIDGE] = "bridge", - [MACVLAN_MODE_VEPA] = "vepa", - [MACVLAN_MODE_PRIVATE] = "private", - [MACVLAN_MODE_PASSTHRU] = "passthru", - }; - - dev = nm_platform_link_get_name(platform, parent); - g_assert(dev); - g_assert_cmpint(lnk->mode, <, G_N_ELEMENTS(modes)); - - success = !nmtstp_run_command("ip link add name %s link %s type %s mode %s %s", - name, - dev, - lnk->tap ? "macvtap" : "macvlan", - modes[lnk->mode], - lnk->no_promisc ? "nopromisc" : ""); - if (success) - pllink = nmtstp_assert_wait_for_link(platform, name, link_type, 100); - } else - success = NMTST_NM_ERR_SUCCESS( - nm_platform_link_macvlan_add(platform, name, parent, lnk, &pllink)); - - _assert_pllink(platform, success, pllink, name, link_type); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_sit_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkSit *lnk) -{ - const NMPlatformLink *pllink = NULL; - gboolean success; - char b1[INET_ADDRSTRLEN]; - char b2[INET_ADDRSTRLEN]; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - const char *dev = ""; - - if (lnk->parent_ifindex) { - const char *parent_name; - - parent_name = nm_platform_link_get_name(platform, lnk->parent_ifindex); - g_assert(parent_name); - dev = nm_sprintf_bufa(100, " dev %s", parent_name); - } - - success = - !nmtstp_run_command("ip tunnel add %s mode sit%s local %s remote %s ttl %u tos %02x %s", - name, - dev, - _nm_utils_inet4_ntop(lnk->local, b1), - _nm_utils_inet4_ntop(lnk->remote, b2), - lnk->ttl, - lnk->tos, - lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); - if (success) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_SIT, 100); - } else - success = NMTST_NM_ERR_SUCCESS(nm_platform_link_sit_add(platform, name, lnk, &pllink)); - - _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_SIT); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_tun_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkTun *lnk, - int * out_fd) -{ - const NMPlatformLink *pllink = NULL; - int err; - int r; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - g_assert(lnk); - g_assert(NM_IN_SET(lnk->type, IFF_TUN, IFF_TAP)); - g_assert(!out_fd || *out_fd == -1); - - if (!lnk->persist) { - /* ip tuntap does not support non-persistent devices. - * - * Add this device only via NMPlatform. */ - if (external_command == -1) - external_command = FALSE; - } - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - g_assert(lnk->persist); - - err = nmtstp_run_command( - "ip tuntap add" - " mode %s" - "%s" /* user */ - "%s" /* group */ - "%s" /* pi */ - "%s" /* vnet_hdr */ - "%s" /* multi_queue */ - " name %s", - lnk->type == IFF_TUN ? "tun" : "tap", - lnk->owner_valid ? nm_sprintf_bufa(100, " user %u", (guint) lnk->owner) : "", - lnk->group_valid ? nm_sprintf_bufa(100, " group %u", (guint) lnk->group) : "", - lnk->pi ? " pi" : "", - lnk->vnet_hdr ? " vnet_hdr" : "", - lnk->multi_queue ? " multi_queue" : "", - name); - /* Older versions of iproute2 don't support adding devices. - * On failure, fallback to using platform code. */ - if (err == 0) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_TUN, 100); - else - g_error("failure to add tun/tap device via ip-route"); - } else { - g_assert(lnk->persist || out_fd); - r = nm_platform_link_tun_add(platform, name, lnk, &pllink, out_fd); - g_assert_cmpint(r, ==, 0); - } - - g_assert(pllink); - g_assert_cmpint(pllink->type, ==, NM_LINK_TYPE_TUN); - g_assert_cmpstr(pllink->name, ==, name); - return pllink; -} - -const NMPlatformLink * -nmtstp_link_vrf_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkVrf *lnk, - gboolean * out_not_supported) -{ - const NMPlatformLink *pllink = NULL; - int r = 0; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - NM_SET_OUT(out_not_supported, FALSE); - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - r = nmtstp_run_command("ip link add %s type vrf table %u", name, lnk->table); - - if (r == 0) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VRF, 100); - else - _LOGI("Adding vrf device via iproute2 failed. Assume iproute2 is not up to the task."); - } - - if (!pllink) { - r = nm_platform_link_vrf_add(platform, name, lnk, &pllink); - if (r == -EOPNOTSUPP) - NM_SET_OUT(out_not_supported, TRUE); - } - - _assert_pllink(platform, r == 0, pllink, name, NM_LINK_TYPE_VRF); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_vxlan_add(NMPlatform * platform, - gboolean external_command, - const char * name, - const NMPlatformLnkVxlan *lnk) -{ - const NMPlatformLink *pllink = NULL; - int err; - int r; - - g_assert(nm_utils_ifname_valid_kernel(name, NULL)); - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - gs_free char *dev = NULL; - char local[NM_UTILS_INET_ADDRSTRLEN]; - char group[NM_UTILS_INET_ADDRSTRLEN]; - - if (lnk->parent_ifindex) - dev = - g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); - - if (lnk->local) - _nm_utils_inet4_ntop(lnk->local, local); - else if (memcmp(&lnk->local6, &in6addr_any, sizeof(in6addr_any))) - _nm_utils_inet6_ntop(&lnk->local6, local); - else - local[0] = '\0'; - - if (lnk->group) - _nm_utils_inet4_ntop(lnk->group, group); - else if (memcmp(&lnk->group6, &in6addr_any, sizeof(in6addr_any))) - _nm_utils_inet6_ntop(&lnk->group6, group); - else - group[0] = '\0'; - - err = nmtstp_run_command("ip link add %s type vxlan id %u %s local %s group %s ttl %u tos " - "%02x dstport %u srcport %u %u ageing %u", - name, - lnk->id, - dev ?: "", - local, - group, - lnk->ttl, - lnk->tos, - lnk->dst_port, - lnk->src_port_min, - lnk->src_port_max, - lnk->ageing); - /* Older versions of iproute2 don't support adding vxlan devices. - * On failure, fallback to using platform code. */ - if (err == 0) - pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VXLAN, 100); - else - _LOGI( - "Adding vxlan device via iproute2 failed. Assume iproute2 is not up to the task."); - } - if (!pllink) { - r = nm_platform_link_vxlan_add(platform, name, lnk, &pllink); - g_assert(NMTST_NM_ERR_SUCCESS(r)); - g_assert(pllink); - } - - g_assert_cmpint(pllink->type, ==, NM_LINK_TYPE_VXLAN); - g_assert_cmpstr(pllink->name, ==, name); - return pllink; -} - -/*****************************************************************************/ - -const NMPlatformLink * -nmtstp_link_get_typed(NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type) -{ - const NMPlatformLink *pllink = NULL; - - _init_platform(&platform, FALSE); - - if (ifindex > 0) { - pllink = nm_platform_link_get(platform, ifindex); - - if (pllink) { - g_assert_cmpint(pllink->ifindex, ==, ifindex); - if (name) - g_assert_cmpstr(name, ==, pllink->name); - } else { - if (name) - g_assert(!nm_platform_link_get_by_ifname(platform, name)); - } - } else { - g_assert(name); - - pllink = nm_platform_link_get_by_ifname(platform, name); - - if (pllink) - g_assert_cmpstr(name, ==, pllink->name); - } - - g_assert(!name || nm_utils_ifname_valid_kernel(name, NULL)); - - if (pllink && link_type != NM_LINK_TYPE_NONE) - g_assert_cmpint(pllink->type, ==, link_type); - - return pllink; -} - -const NMPlatformLink * -nmtstp_link_get(NMPlatform *platform, int ifindex, const char *name) -{ - return nmtstp_link_get_typed(platform, ifindex, name, NM_LINK_TYPE_NONE); -} - -/*****************************************************************************/ - -void -nmtstp_link_delete(NMPlatform *platform, - gboolean external_command, - int ifindex, - const char *name, - gboolean require_exist) -{ - gint64 end_time; - const NMPlatformLink *pllink; - gboolean success; - gs_free char * name_copy = NULL; - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - pllink = nmtstp_link_get(platform, ifindex, name); - - if (!pllink) { - g_assert(!require_exist); - return; - } - - name = name_copy = g_strdup(pllink->name); - ifindex = pllink->ifindex; - - if (external_command) { - nmtstp_run_command_check("ip link delete %s", name); - } else { - success = nm_platform_link_delete(platform, ifindex); - g_assert(success); - } - - /* Let's wait until we get the result */ - end_time = nm_utils_get_monotonic_timestamp_msec() + 250; - do { - if (external_command) - nm_platform_process_events(platform); - - if (!nm_platform_link_get(platform, ifindex)) { - g_assert(!nm_platform_link_get_by_ifname(platform, name)); - break; - } - - /* 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); -} - -/*****************************************************************************/ - -void -nmtstp_link_set_updown(NMPlatform *platform, gboolean external_command, int ifindex, gboolean up) -{ - const NMPlatformLink *plink; - gint64 end_time; - - external_command = nmtstp_run_command_check_external(external_command); - - _init_platform(&platform, external_command); - - if (external_command) { - const char *ifname; - - ifname = nm_platform_link_get_name(platform, ifindex); - g_assert(ifname); - - nmtstp_run_command_check("ip link set %s %s", ifname, up ? "up" : "down"); - } else { - if (up) - g_assert(nm_platform_link_set_up(platform, ifindex, NULL)); - else - g_assert(nm_platform_link_set_down(platform, ifindex)); - } - - /* Let's wait until we get the result */ - end_time = nm_utils_get_monotonic_timestamp_msec() + 250; - do { - if (external_command) - nm_platform_process_events(platform); - - /* let's wait until we see the address as we added it. */ - plink = nm_platform_link_get(platform, ifindex); - g_assert(plink); - - if (NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP) == !!up) - break; - - /* 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); -} - -/*****************************************************************************/ - -gboolean -nmtstp_kernel_support_get(NMPlatformKernelSupportType type) -{ - const NMPlatformLink *pllink; - NMTernary v; - - v = nm_platform_kernel_support_get_full(type, FALSE); - if (v != NM_TERNARY_DEFAULT) - return v != NM_TERNARY_FALSE; - - switch (type) { - case NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED: - pllink = nmtstp_link_bridge_add(NULL, -1, "br-test-11", &nm_platform_lnk_bridge_default); - nmtstp_link_delete(NULL, -1, pllink->ifindex, NULL, TRUE); - v = nm_platform_kernel_support_get_full(type, FALSE); - g_assert(v != NM_TERNARY_DEFAULT); - return v; - default: - g_assert_not_reached(); - } -} - -/*****************************************************************************/ - -struct _NMTstpNamespaceHandle { - pid_t pid; - int pipe_fd; -}; - -NMTstpNamespaceHandle * -nmtstp_namespace_create(int unshare_flags, GError **error) -{ - NMTstpNamespaceHandle *ns_handle; - int e; - int errsv; - pid_t pid, pid2; - int pipefd_c2p[2]; - int pipefd_p2c[2]; - ssize_t r; - - e = pipe2(pipefd_c2p, O_CLOEXEC); - if (e != 0) { - errsv = errno; - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "pipe() failed with %d (%s)", - errsv, - nm_strerror_native(errsv)); - return FALSE; - } - - e = pipe2(pipefd_p2c, O_CLOEXEC); - if (e != 0) { - errsv = errno; - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "pipe() failed with %d (%s)", - errsv, - nm_strerror_native(errsv)); - nm_close(pipefd_c2p[0]); - nm_close(pipefd_c2p[1]); - return FALSE; - } - - pid = fork(); - if (pid < 0) { - errsv = errno; - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "fork() failed with %d (%s)", - errsv, - nm_strerror_native(errsv)); - nm_close(pipefd_c2p[0]); - nm_close(pipefd_c2p[1]); - nm_close(pipefd_p2c[0]); - nm_close(pipefd_p2c[1]); - return FALSE; - } - - if (pid == 0) { - char read_buf[1]; - - nm_close(pipefd_c2p[0]); /* close read-end */ - nm_close(pipefd_p2c[1]); /* close write-end */ - - if (unshare(unshare_flags) != 0) { - errsv = errno; - if (errsv == 0) - errsv = -1; - } else - errsv = 0; - - /* sync with parent process and send result. */ - do { - r = write(pipefd_c2p[1], &errsv, sizeof(errsv)); - } while (r < 0 && errno == EINTR); - if (r != sizeof(errsv)) { - errsv = errno; - if (errsv == 0) - errsv = -2; - } - nm_close(pipefd_c2p[1]); - - /* wait until parent process terminates (or kills us). */ - if (errsv == 0) { - do { - r = read(pipefd_p2c[0], read_buf, sizeof(read_buf)); - } while (r < 0 && errno == EINTR); - } - nm_close(pipefd_p2c[0]); - _exit(0); - } - - nm_close(pipefd_c2p[1]); /* close write-end */ - nm_close(pipefd_p2c[0]); /* close read-end */ - - /* sync with child process. */ - do { - r = read(pipefd_c2p[0], &errsv, sizeof(errsv)); - } while (r < 0 && errno == EINTR); - - nm_close(pipefd_c2p[0]); - - if (r != sizeof(errsv) || errsv != 0) { - int status; - - if (r != sizeof(errsv)) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "child process failed for unknown reason"); - } else { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "child process signaled failure %d (%s)", - errsv, - nm_strerror_native(errsv)); - } - nm_close(pipefd_p2c[1]); - kill(pid, SIGKILL); - do { - pid2 = waitpid(pid, &status, 0); - } while (pid2 == -1 && errno == EINTR); - return FALSE; - } - - ns_handle = g_new0(NMTstpNamespaceHandle, 1); - ns_handle->pid = pid; - ns_handle->pipe_fd = pipefd_p2c[1]; - return ns_handle; -} - -pid_t -nmtstp_namespace_handle_get_pid(NMTstpNamespaceHandle *ns_handle) -{ - g_return_val_if_fail(ns_handle, 0); - g_return_val_if_fail(ns_handle->pid > 0, 0); - - return ns_handle->pid; -} - -void -nmtstp_namespace_handle_release(NMTstpNamespaceHandle *ns_handle) -{ - pid_t pid; - int status; - - if (!ns_handle) - return; - - g_return_if_fail(ns_handle->pid > 0); - - nm_close(ns_handle->pipe_fd); - ns_handle->pipe_fd = 0; - - kill(ns_handle->pid, SIGKILL); - - do { - pid = waitpid(ns_handle->pid, &status, 0); - } while (pid == -1 && errno == EINTR); - ns_handle->pid = 0; - - g_free(ns_handle); -} - -int -nmtstp_namespace_get_fd_for_process(pid_t pid, const char *ns_name) -{ - char p[1000]; - - g_return_val_if_fail(pid > 0, 0); - g_return_val_if_fail(ns_name && ns_name[0] && strlen(ns_name) < 50, 0); - - nm_sprintf_buf(p, "/proc/%lu/ns/%s", (unsigned long) pid, ns_name); - - return open(p, O_RDONLY | O_CLOEXEC); -} - -/*****************************************************************************/ - -void -nmtstp_netns_select_random(NMPlatform **platforms, gsize n_platforms, NMPNetns **netns) -{ - int i; - - g_assert(platforms); - g_assert(n_platforms && n_platforms <= G_MAXINT32); - g_assert(netns && !*netns); - for (i = 0; i < n_platforms; i++) - g_assert(NM_IS_PLATFORM(platforms[i])); - - i = nmtst_get_rand_uint32() % (n_platforms + 1); - if (i == 0) - return; - g_assert(nm_platform_netns_push(platforms[i - 1], netns)); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -static gboolean -unshare_user(void) -{ - FILE *f; - uid_t uid = geteuid(); - gid_t gid = getegid(); - - /* Already a root? */ - if (gid == 0 && uid == 0) - return TRUE; - - /* Become a root in new user NS. */ - if (unshare(CLONE_NEWUSER) != 0) - return FALSE; - - /* Since Linux 3.19 we have to disable setgroups() in order to map users. - * Just proceed if the file is not there. */ - f = fopen("/proc/self/setgroups", "we"); - if (f) { - fprintf(f, "deny"); - fclose(f); - } - - /* Map current UID to root in NS to be created. */ - f = fopen("/proc/self/uid_map", "we"); - if (!f) - return FALSE; - fprintf(f, "0 %d 1", uid); - fclose(f); - - /* Map current GID to root in NS to be created. */ - f = fopen("/proc/self/gid_map", "we"); - if (!f) - return FALSE; - fprintf(f, "0 %d 1", gid); - fclose(f); - - return TRUE; -} - -int -main(int argc, char **argv) -{ - int result; - const char *program = *argv; - - _nmtstp_init_tests(&argc, &argv); - - if (nmtstp_is_root_test() && (geteuid() != 0 || getegid() != 0)) { - if (g_getenv("NMTST_FORCE_REAL_ROOT") || !unshare_user()) { - /* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */ - nmtst_reexec_sudo(); - -#ifdef REQUIRE_ROOT_TESTS - g_print("Fail test: requires root privileges (%s)\n", program); - return EXIT_FAILURE; -#else - g_print("Skipping test: requires root privileges (%s)\n", program); - return g_test_run(); -#endif - } - } - - if (nmtstp_is_root_test() && !g_getenv("NMTST_NO_UNSHARE")) { - int errsv; - - if (unshare(CLONE_NEWNET | CLONE_NEWNS) != 0) { - errsv = errno; - g_error("unshare(CLONE_NEWNET|CLONE_NEWNS) failed with %s (%d)", - nm_strerror_native(errsv), - errsv); - } - - /* We need a read-only /sys so that the platform knows there's no udev. */ - mount(NULL, "/sys", "sysfs", MS_SLAVE, NULL); - if (mount("sys", "/sys", "sysfs", MS_RDONLY, NULL) != 0) { - errsv = errno; - g_error("mount(\"/sys\") failed with %s (%d)", nm_strerror_native(errsv), errsv); - } - } - - nmtstp_setup_platform(); - - _nmtstp_setup_tests(); - - result = g_test_run(); - - nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, DEVICE_NAME, FALSE); - - g_object_unref(NM_PLATFORM_GET); - return result; -} |