/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2015 Red Hat, Inc.
*/
#include "nm-default.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 = &g_array_index(addresses, NMPlatformIP4Address, 0);
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 = &g_array_index(addresses, NMPlatformIP6Address, 0);
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_set_up(NM_PLATFORM_GET, DEVICE_IFINDEX, NULL));
/* 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_set_up(NM_PLATFORM_GET, ifindex, NULL));
accept_signals(address_removed, 0, G_MAXINT);
accept_signals(address_added, 0, G_MAXINT);
/* Add/delete notification */
nmtstp_ip4_address_add(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_set_up(NM_PLATFORM_GET, ifindex, NULL));
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, 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);
}