/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ #include "src/core/nm-default-daemon.h" #include "test-common.h" #define IP4_ADDRESS "192.0.2.1" #define IP4_ADDRESS_PEER "192.0.2.2" #define IP4_ADDRESS_PEER2 "192.0.3.1" #define IP4_PLEN 24 #define IP6_ADDRESS "2001:db8:a:b:1:2:3:4" #define IP6_PLEN 64 #define DEVICE_IFINDEX NMTSTP_ENV1_IFINDEX #define EX NMTSTP_ENV1_EX /*****************************************************************************/ static void ip4_address_callback(NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, SignalData *data) { g_assert(received); g_assert_cmpint(received->ifindex, ==, ifindex); g_assert(data && data->name); g_assert_cmpstr(data->name, ==, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED); if (data->ifindex && data->ifindex != received->ifindex) return; if (data->change_type != change_type) return; if (data->loop) g_main_loop_quit(data->loop); data->received_count++; _LOGD("Received signal '%s' %dth time.", data->name, data->received_count); } static void ip6_address_callback(NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *received, NMPlatformSignalChangeType change_type, SignalData *data) { g_assert(received); g_assert_cmpint(received->ifindex, ==, ifindex); g_assert(data && data->name); g_assert_cmpstr(data->name, ==, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED); if (data->ifindex && data->ifindex != received->ifindex) return; if (data->change_type != change_type) return; if (data->loop) g_main_loop_quit(data->loop); data->received_count++; _LOGD("Received signal '%s' %dth time.", data->name, data->received_count); } /*****************************************************************************/ static void test_ip4_address_general(void) { const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal_ifindex(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback, ifindex); SignalData *address_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_address_callback, ifindex); SignalData *address_removed = add_signal_ifindex(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback, ifindex); GArray *addresses; NMPlatformIP4Address *address; in_addr_t addr; guint32 lifetime = 2000; guint32 preferred = 1000; inet_pton(AF_INET, IP4_ADDRESS, &addr); /* Add address */ g_assert(!nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); g_assert(nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal(address_added); /* Add address again (aka update) */ nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr, lifetime + 100, preferred + 50, 0, NULL); accept_signals(address_changed, 0, 1); /* Test address listing */ addresses = nmtstp_platform_ip4_address_get_all(NM_PLATFORM_GET, ifindex); g_assert(addresses); g_assert_cmpint(addresses->len, ==, 1); address = &nm_g_array_first(addresses, NMPlatformIP4Address); g_assert_cmpint(address->ifindex, ==, ifindex); g_assert_cmphex(address->address, ==, addr); g_assert_cmphex(address->peer_address, ==, addr); g_assert_cmpint(address->plen, ==, IP4_PLEN); g_array_unref(addresses); /* Remove address */ nmtstp_ip4_address_del(NULL, EX, ifindex, addr, IP4_PLEN, addr); g_assert(!nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal(address_removed); /* Remove address again */ nmtstp_ip4_address_del(NULL, EX, ifindex, addr, IP4_PLEN, addr); free_signal(address_added); free_signal(address_changed); free_signal(address_removed); } static void test_ip6_address_general(void) { const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal_ifindex(NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback, ifindex); SignalData *address_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_address_callback, ifindex); SignalData *address_removed = add_signal_ifindex(NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback, ifindex); GArray *addresses; NMPlatformIP6Address *address; struct in6_addr addr; guint32 lifetime = 2000; guint32 preferred = 1000; guint flags = 0; inet_pton(AF_INET6, IP6_ADDRESS, &addr); /* Add address */ g_assert(!nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); nmtstp_ip6_address_add(NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); g_assert(nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); accept_signal(address_added); /* Add address again (aka update) */ nmtstp_ip6_address_add(NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); accept_signals(address_changed, 0, 2); /* Test address listing */ addresses = nmtstp_platform_ip6_address_get_all(NM_PLATFORM_GET, ifindex); g_assert(addresses); g_assert_cmpint(addresses->len, ==, 1); address = &nm_g_array_first(addresses, NMPlatformIP6Address); g_assert_cmpint(address->ifindex, ==, ifindex); g_assert(!memcmp(&address->address, &addr, sizeof(addr))); g_assert_cmpint(address->plen, ==, IP6_PLEN); g_array_unref(addresses); /* Remove address */ nmtstp_ip6_address_del(NULL, EX, ifindex, addr, IP6_PLEN); g_assert(!nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); accept_signal(address_removed); /* Remove address again */ nmtstp_ip6_address_del(NULL, EX, ifindex, addr, IP6_PLEN); /* ensure not pending signal. */ accept_signals(address_changed, 0, 1); free_signal(address_added); free_signal(address_changed); free_signal(address_removed); } static void test_ip4_address_general_2(void) { const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback); SignalData *address_removed = add_signal(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback); in_addr_t addr; guint32 lifetime = 2000; guint32 preferred = 1000; inet_pton(AF_INET, IP4_ADDRESS, &addr); g_assert(ifindex > 0); /* Looks like addresses are not announced by kernel when the interface * is down. Link-local IPv6 address is automatically added. */ g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, DEVICE_IFINDEX, IFF_UP, TRUE) >= 0); /* Add/delete notification */ nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); accept_signal(address_added); g_assert(nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); nmtstp_ip4_address_del(NULL, EX, ifindex, addr, IP4_PLEN, addr); accept_signal(address_removed); g_assert(!nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); /* Add/delete conflict */ nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); g_assert(nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal(address_added); free_signal(address_added); free_signal(address_removed); } static void test_ip6_address_general_2(void) { const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal(NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback); SignalData *address_removed = add_signal(NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback); struct in6_addr addr; guint32 lifetime = 2000; guint32 preferred = 1000; guint flags = 0; inet_pton(AF_INET6, IP6_ADDRESS, &addr); /* Add/delete notification */ nmtstp_ip6_address_add(NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, 0); accept_signal(address_added); g_assert(nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); nmtstp_ip6_address_del(NULL, EX, ifindex, addr, IP6_PLEN); accept_signal(address_removed); g_assert(!nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); /* Add/delete conflict */ nmtstp_ip6_address_add(NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, 0); accept_signal(address_added); g_assert(nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); nmtstp_ip6_address_add(NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); ensure_no_signal(address_added); g_assert(nm_platform_ip6_address_get(NM_PLATFORM_GET, ifindex, &addr)); free_signal(address_added); free_signal(address_removed); } /*****************************************************************************/ static void test_ip4_address_peer(void) { const int ifindex = DEVICE_IFINDEX; SignalData *address_added = add_signal(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback); SignalData *address_removed = add_signal(NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback); in_addr_t addr, addr_peer, addr_peer2; guint32 lifetime = 2000; guint32 preferred = 1000; const NMPlatformIP4Address *a; inet_pton(AF_INET, IP4_ADDRESS, &addr); inet_pton(AF_INET, IP4_ADDRESS_PEER, &addr_peer); inet_pton(AF_INET, IP4_ADDRESS_PEER2, &addr_peer2); g_assert(ifindex > 0); g_assert(addr != addr_peer); g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, TRUE) >= 0); accept_signals(address_removed, 0, G_MAXINT); accept_signals(address_added, 0, G_MAXINT); /* Add/delete notification */ nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr_peer, lifetime, preferred, 0, NULL); accept_signal(address_added); a = nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer); g_assert(a); g_assert(!nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2)); nmtstp_ip_address_assert_lifetime((NMPlatformIPAddress *) a, -1, lifetime, preferred); nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr_peer2, lifetime, preferred, 0, NULL); accept_signal(address_added); g_assert(nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); a = nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2); g_assert(a); nmtstp_ip_address_assert_lifetime((NMPlatformIPAddress *) a, -1, lifetime, preferred); g_assert(addr != addr_peer); nmtstp_ip4_address_del(NULL, EX, ifindex, addr, IP4_PLEN, addr_peer); accept_signal(address_removed); g_assert(!nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); g_assert(nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2)); free_signal(address_added); free_signal(address_removed); } /*****************************************************************************/ static void test_ip4_address_peer_zero(void) { const int ifindex = DEVICE_IFINDEX; in_addr_t addr, addr_peer; guint32 lifetime = 2000; guint32 preferred = 1000; const gint8 plen = 24; const char *label = NULL; in_addr_t peers[3], r_peers[3]; int i; GArray *addrs; g_assert(ifindex > 0); inet_pton(AF_INET, "192.168.5.2", &addr); inet_pton(AF_INET, "192.168.6.2", &addr_peer); peers[0] = addr; peers[1] = addr_peer; peers[2] = 0; g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, TRUE) >= 0); nmtst_rand_perm(NULL, r_peers, peers, sizeof(peers[0]), G_N_ELEMENTS(peers)); for (i = 0; i < G_N_ELEMENTS(peers); i++) { g_assert(!nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i])); nmtstp_ip4_address_add(NULL, EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, 0, label); addrs = nmtstp_platform_ip4_address_get_all(NM_PLATFORM_GET, ifindex); g_assert(addrs); g_assert_cmpint(addrs->len, ==, i + 1); g_array_unref(addrs); } if (nmtst_is_debug() && nmtstp_is_root_test()) nmtstp_run_command_check("ip address show dev %s", DEVICE_NAME); nmtst_rand_perm(NULL, r_peers, peers, sizeof(peers[0]), G_N_ELEMENTS(peers)); for (i = 0; i < G_N_ELEMENTS(peers); i++) { g_assert(nm_platform_ip4_address_get(NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i])); nmtstp_ip4_address_del(NULL, EX, ifindex, addr, plen, r_peers[i]); addrs = nmtstp_platform_ip4_address_get_all(NM_PLATFORM_GET, ifindex); g_assert(addrs); g_assert_cmpint(addrs->len, ==, G_N_ELEMENTS(peers) - i - 1); g_array_unref(addrs); } } /*****************************************************************************/ NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; void _nmtstp_init_tests(int *argc, char ***argv) { nmtst_init_with_logging(argc, argv, NULL, "ALL"); } /***************************************************************************** * SETUP TESTS *****************************************************************************/ void _nmtstp_setup_tests(void) { #define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, 1, FALSE) add_test_func("/address/ipv4/general", test_ip4_address_general); add_test_func("/address/ipv6/general", test_ip6_address_general); add_test_func("/address/ipv4/general-2", test_ip4_address_general_2); add_test_func("/address/ipv6/general-2", test_ip6_address_general_2); add_test_func("/address/ipv4/peer", test_ip4_address_peer); add_test_func("/address/ipv4/peer/zero", test_ip4_address_peer_zero); }