mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-27 08:10:08 +01:00
https://bugzilla.redhat.com/show_bug.cgi?id=1778590
Signed-off-by: Antonio Cardace <acardace@redhat.com>
(cherry picked from commit 516c623618)
3819 lines
152 KiB
C
3819 lines
152 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* Copyright (C) 2016 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include <sched.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <linux/if_tun.h>
|
|
|
|
#include "nm-glib-aux/nm-io-utils.h"
|
|
#include "platform/nmp-object.h"
|
|
#include "platform/nmp-netns.h"
|
|
#include "platform/nm-platform-utils.h"
|
|
|
|
#include "test-common.h"
|
|
#include "nm-test-utils-core.h"
|
|
|
|
#define LO_INDEX 1
|
|
#define LO_NAME "lo"
|
|
#define LO_TYPEDESC "loopback"
|
|
|
|
#define DUMMY_TYPEDESC "dummy"
|
|
#define BOGUS_NAME "nm-bogus-device"
|
|
#define BOGUS_IFINDEX INT_MAX
|
|
#define SLAVE_NAME "nm-test-slave"
|
|
#define PARENT_NAME "nm-test-parent"
|
|
#define VLAN_ID 4077
|
|
#define VLAN_FLAGS 0
|
|
#define MTU 1357
|
|
|
|
#define _ADD_DUMMY(platform, name) \
|
|
g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add((platform), (name), NULL)))
|
|
|
|
static void
|
|
test_bogus(void)
|
|
{
|
|
size_t addrlen;
|
|
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, BOGUS_NAME));
|
|
g_assert(!nm_platform_link_delete(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
g_assert(!nm_platform_link_get_ifindex(NM_PLATFORM_GET, BOGUS_NAME));
|
|
g_assert(!nm_platform_link_get_name(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
g_assert(!nm_platform_link_get_type(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
g_assert(!nm_platform_link_get_type_name(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_set_up(NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
|
|
|
|
g_assert(!nm_platform_link_set_down(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_set_arp(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_set_noarp(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_get_address(NM_PLATFORM_GET, BOGUS_IFINDEX, &addrlen));
|
|
g_assert(!addrlen);
|
|
g_assert(!nm_platform_link_get_address(NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
|
|
|
|
g_assert(!NMTST_NM_ERR_SUCCESS(nm_platform_link_set_mtu(NM_PLATFORM_GET, BOGUS_IFINDEX, MTU)));
|
|
|
|
g_assert(!nm_platform_link_get_mtu(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_supports_carrier_detect(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
g_assert(!nm_platform_link_supports_vlans(NM_PLATFORM_GET, BOGUS_IFINDEX));
|
|
|
|
g_assert(!nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
|
|
g_assert(!nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
|
|
g_assert(!nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
|
|
}
|
|
|
|
static void
|
|
test_loopback(void)
|
|
{
|
|
g_assert(nm_platform_link_get_by_ifname(NM_PLATFORM_GET, LO_NAME));
|
|
g_assert_cmpint(nm_platform_link_get_type(NM_PLATFORM_GET, LO_INDEX),
|
|
==,
|
|
NM_LINK_TYPE_LOOPBACK);
|
|
g_assert_cmpint(nm_platform_link_get_ifindex(NM_PLATFORM_GET, LO_NAME), ==, LO_INDEX);
|
|
g_assert_cmpstr(nm_platform_link_get_name(NM_PLATFORM_GET, LO_INDEX), ==, LO_NAME);
|
|
g_assert_cmpstr(nm_platform_link_get_type_name(NM_PLATFORM_GET, LO_INDEX), ==, LO_TYPEDESC);
|
|
|
|
g_assert(nm_platform_link_supports_carrier_detect(NM_PLATFORM_GET, LO_INDEX));
|
|
g_assert(!nm_platform_link_supports_vlans(NM_PLATFORM_GET, LO_INDEX));
|
|
}
|
|
|
|
static gboolean
|
|
software_add(NMLinkType link_type, const char *name)
|
|
{
|
|
switch (link_type) {
|
|
case NM_LINK_TYPE_DUMMY:
|
|
return NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add(NM_PLATFORM_GET, name, NULL));
|
|
case NM_LINK_TYPE_BRIDGE:
|
|
return NMTST_NM_ERR_SUCCESS(nm_platform_link_bridge_add(NM_PLATFORM_GET,
|
|
name,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&nm_platform_lnk_bridge_default,
|
|
NULL));
|
|
case NM_LINK_TYPE_BOND:
|
|
{
|
|
gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0");
|
|
int r;
|
|
|
|
r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, NULL);
|
|
|
|
/* Check that bond0 is *not* automatically created. */
|
|
if (!bond0_exists)
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0"));
|
|
return r >= 0;
|
|
}
|
|
case NM_LINK_TYPE_TEAM:
|
|
return NMTST_NM_ERR_SUCCESS(nm_platform_link_team_add(NM_PLATFORM_GET, name, NULL));
|
|
case NM_LINK_TYPE_VLAN:
|
|
{
|
|
SignalData *parent_added;
|
|
SignalData *parent_changed;
|
|
|
|
/* Don't call link_callback for the bridge interface */
|
|
parent_added = add_signal_ifname(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_ADDED,
|
|
link_callback,
|
|
PARENT_NAME);
|
|
if (NMTST_NM_ERR_SUCCESS(nm_platform_link_bridge_add(NM_PLATFORM_GET,
|
|
PARENT_NAME,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&nm_platform_lnk_bridge_default,
|
|
NULL)))
|
|
accept_signal(parent_added);
|
|
free_signal(parent_added);
|
|
|
|
{
|
|
int parent_ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, PARENT_NAME);
|
|
gboolean was_up = nm_platform_link_is_up(NM_PLATFORM_GET, parent_ifindex);
|
|
|
|
parent_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_CHANGED,
|
|
link_callback,
|
|
parent_ifindex);
|
|
g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, parent_ifindex, NULL));
|
|
if (was_up) {
|
|
/* when NM is running in the background, it will mess with addrgenmode which might cause additional signals. */
|
|
accept_signals(parent_changed, 0, 1);
|
|
} else
|
|
accept_signals(parent_changed, 1, 2);
|
|
free_signal(parent_changed);
|
|
|
|
return NMTST_NM_ERR_SUCCESS(
|
|
nm_platform_link_vlan_add(NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL));
|
|
}
|
|
}
|
|
default:
|
|
g_error("Link type %d unhandled.", link_type);
|
|
}
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
static void
|
|
test_link_changed_signal_cb(NMPlatform * platform,
|
|
int obj_type_i,
|
|
int ifindex,
|
|
const NMPlatformIP4Route *route,
|
|
int change_type_i,
|
|
gboolean * p_test_link_changed_signal_arg)
|
|
{
|
|
const NMPObjectType obj_type = obj_type_i;
|
|
const NMPlatformSignalChangeType change_type = change_type_i;
|
|
|
|
/* test invocation of platform signals with multiple listeners
|
|
* connected to the signal. Platform signals have enum-typed
|
|
* arguments and there seem to be an issue with invoking such
|
|
* signals on s390x and ppc64 archs.
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1260577
|
|
*
|
|
* As the test shows, the failure is not reproducible for
|
|
* platform signals.
|
|
*/
|
|
g_assert(NM_IS_PLATFORM(platform));
|
|
g_assert(platform == NM_PLATFORM_GET);
|
|
|
|
g_assert(ifindex > 0);
|
|
g_assert(route);
|
|
|
|
g_assert_cmpint(obj_type, ==, NMP_OBJECT_TYPE_LINK);
|
|
|
|
g_assert_cmpint((gint64) change_type, !=, (gint64) 0);
|
|
g_assert_cmpint(change_type, !=, NM_PLATFORM_SIGNAL_NONE);
|
|
|
|
*p_test_link_changed_signal_arg = TRUE;
|
|
}
|
|
|
|
static void
|
|
test_slave(int master, int type, SignalData *master_changed)
|
|
{
|
|
int ifindex;
|
|
SignalData *link_added = add_signal_ifname(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_ADDED,
|
|
link_callback,
|
|
SLAVE_NAME);
|
|
SignalData *link_changed, *link_removed;
|
|
char * value;
|
|
NMLinkType link_type = nm_platform_link_get_type(NM_PLATFORM_GET, master);
|
|
gboolean test_link_changed_signal_arg1;
|
|
gboolean test_link_changed_signal_arg2;
|
|
|
|
g_assert(NM_IN_SET(link_type, NM_LINK_TYPE_TEAM, NM_LINK_TYPE_BOND, NM_LINK_TYPE_BRIDGE));
|
|
|
|
g_assert(software_add(type, SLAVE_NAME));
|
|
ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, SLAVE_NAME);
|
|
g_assert(ifindex > 0);
|
|
link_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_CHANGED,
|
|
link_callback,
|
|
ifindex);
|
|
link_removed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_REMOVED,
|
|
link_callback,
|
|
ifindex);
|
|
accept_signal(link_added);
|
|
|
|
/* Set the slave up to see whether master's IFF_LOWER_UP is set correctly.
|
|
*
|
|
* See https://bugzilla.redhat.com/show_bug.cgi?id=910348
|
|
*/
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_set_down(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
ensure_no_signal(link_changed);
|
|
|
|
/* Enslave */
|
|
link_changed->ifindex = ifindex;
|
|
g_assert(nm_platform_link_enslave(NM_PLATFORM_GET, master, ifindex));
|
|
g_assert_cmpint(nm_platform_link_get_master(NM_PLATFORM_GET, ifindex), ==, master);
|
|
|
|
accept_signals(link_changed, 1, 3);
|
|
accept_signals(master_changed, 0, 2);
|
|
|
|
/* enslaveing brings put the slave */
|
|
if (NM_IN_SET(link_type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM))
|
|
g_assert(nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
else
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
|
|
test_link_changed_signal_arg1 = FALSE;
|
|
test_link_changed_signal_arg2 = FALSE;
|
|
g_signal_connect(NM_PLATFORM_GET,
|
|
NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
G_CALLBACK(test_link_changed_signal_cb),
|
|
&test_link_changed_signal_arg1);
|
|
g_signal_connect(NM_PLATFORM_GET,
|
|
NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
G_CALLBACK(test_link_changed_signal_cb),
|
|
&test_link_changed_signal_arg2);
|
|
|
|
/* Set master up */
|
|
g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, master, NULL));
|
|
g_assert(nm_platform_link_is_up(NM_PLATFORM_GET, master));
|
|
accept_signals(master_changed, 1, 3);
|
|
|
|
g_signal_handlers_disconnect_by_func(NM_PLATFORM_GET,
|
|
G_CALLBACK(test_link_changed_signal_cb),
|
|
&test_link_changed_signal_arg1);
|
|
g_signal_handlers_disconnect_by_func(NM_PLATFORM_GET,
|
|
G_CALLBACK(test_link_changed_signal_cb),
|
|
&test_link_changed_signal_arg2);
|
|
g_assert(test_link_changed_signal_arg1);
|
|
g_assert(test_link_changed_signal_arg2);
|
|
|
|
/* Master with a disconnected slave is disconnected
|
|
*
|
|
* For some reason, bonding and teaming slaves are automatically set up. We
|
|
* need to set them back down for this test.
|
|
*/
|
|
switch (nm_platform_link_get_type(NM_PLATFORM_GET, master)) {
|
|
case NM_LINK_TYPE_BOND:
|
|
case NM_LINK_TYPE_TEAM:
|
|
g_assert(nm_platform_link_set_down(NM_PLATFORM_GET, ifindex));
|
|
accept_signal(link_changed);
|
|
accept_signals(master_changed, 0, 3);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
if (nmtstp_is_root_test() && nm_platform_link_is_connected(NM_PLATFORM_GET, master)) {
|
|
if (nm_platform_link_get_type(NM_PLATFORM_GET, master) == NM_LINK_TYPE_TEAM) {
|
|
/* Older team versions (e.g. Fedora 17) have a bug that team master stays
|
|
* IFF_LOWER_UP even if its slave is down. Double check it with iproute2 and if
|
|
* `ip link` also claims master to be up, accept it. */
|
|
char *stdout_str = NULL;
|
|
|
|
nmtst_spawn_sync(NULL,
|
|
&stdout_str,
|
|
NULL,
|
|
0,
|
|
"/sbin/ip",
|
|
"link",
|
|
"show",
|
|
"dev",
|
|
nm_platform_link_get_name(NM_PLATFORM_GET, master));
|
|
|
|
g_assert(strstr(stdout_str, "LOWER_UP"));
|
|
g_free(stdout_str);
|
|
} else
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
/* Set slave up and see if master gets up too */
|
|
g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, master));
|
|
accept_signals(link_changed, 1, 3);
|
|
/* NM running, can cause additional change of addrgenmode */
|
|
accept_signals(master_changed, 0, 3);
|
|
|
|
/* Enslave again
|
|
*
|
|
* Gracefully succeed if already enslaved.
|
|
*/
|
|
ensure_no_signal(link_changed);
|
|
g_assert(nm_platform_link_enslave(NM_PLATFORM_GET, master, ifindex));
|
|
accept_signals(link_changed, 0, 2);
|
|
accept_signals(master_changed, 0, 2);
|
|
|
|
/* Set slave option */
|
|
switch (type) {
|
|
case NM_LINK_TYPE_BRIDGE:
|
|
if (nmtstp_is_sysfs_writable()) {
|
|
g_assert(
|
|
nm_platform_sysctl_slave_set_option(NM_PLATFORM_GET, ifindex, "priority", "614"));
|
|
value = nm_platform_sysctl_slave_get_option(NM_PLATFORM_GET, ifindex, "priority");
|
|
g_assert_cmpstr(value, ==, "614");
|
|
g_free(value);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Release */
|
|
ensure_no_signal(link_added);
|
|
ensure_no_signal(link_changed);
|
|
ensure_no_signal(link_removed);
|
|
g_assert(nm_platform_link_release(NM_PLATFORM_GET, master, ifindex));
|
|
g_assert_cmpint(nm_platform_link_get_master(NM_PLATFORM_GET, ifindex), ==, 0);
|
|
if (link_changed->received_count > 0) {
|
|
accept_signals(link_added, 0, 1);
|
|
accept_signals(link_changed, 1, 5);
|
|
accept_signals(link_removed, 0, 1);
|
|
} else {
|
|
/* Due to https://bugzilla.redhat.com/show_bug.cgi?id=1285719 , kernel might send a
|
|
* wrong RTM_DELLINK message so that we instead see an removed+added signal. */
|
|
accept_signal(link_added);
|
|
ensure_no_signal(link_changed);
|
|
accept_signal(link_removed);
|
|
}
|
|
accept_signals(master_changed, 0, 3);
|
|
|
|
ensure_no_signal(master_changed);
|
|
|
|
/* Release again */
|
|
ensure_no_signal(link_changed);
|
|
g_assert(!nm_platform_link_release(NM_PLATFORM_GET, master, ifindex));
|
|
|
|
ensure_no_signal(master_changed);
|
|
|
|
/* Remove */
|
|
ensure_no_signal(link_added);
|
|
ensure_no_signal(link_changed);
|
|
ensure_no_signal(link_removed);
|
|
nmtstp_link_delete(NULL, -1, ifindex, NULL, TRUE);
|
|
accept_signals(master_changed, 0, 1);
|
|
accept_signals(link_changed, 0, 1);
|
|
accept_signal(link_removed);
|
|
|
|
free_signal(link_added);
|
|
free_signal(link_changed);
|
|
free_signal(link_removed);
|
|
}
|
|
|
|
static void
|
|
test_software(NMLinkType link_type, const char *link_typename)
|
|
{
|
|
int ifindex;
|
|
char *value;
|
|
int vlan_parent = -1, vlan_id;
|
|
|
|
SignalData *link_added, *link_changed, *link_removed;
|
|
|
|
/* Add */
|
|
link_added = add_signal_ifname(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_ADDED,
|
|
link_callback,
|
|
DEVICE_NAME);
|
|
g_assert(software_add(link_type, DEVICE_NAME));
|
|
accept_signal(link_added);
|
|
g_assert(nm_platform_link_get_by_ifname(NM_PLATFORM_GET, DEVICE_NAME));
|
|
ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME);
|
|
g_assert(ifindex >= 0);
|
|
g_assert_cmpint(nm_platform_link_get_type(NM_PLATFORM_GET, ifindex), ==, link_type);
|
|
g_assert_cmpstr(nm_platform_link_get_type_name(NM_PLATFORM_GET, ifindex), ==, link_typename);
|
|
link_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_CHANGED,
|
|
link_callback,
|
|
ifindex);
|
|
link_removed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_REMOVED,
|
|
link_callback,
|
|
ifindex);
|
|
if (link_type == NM_LINK_TYPE_VLAN) {
|
|
const NMPlatformLink * plink;
|
|
const NMPlatformLnkVlan *plnk;
|
|
|
|
plnk = nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, ifindex, &plink);
|
|
g_assert(plnk);
|
|
g_assert(plink);
|
|
|
|
vlan_parent = plink->parent;
|
|
vlan_id = plnk->id;
|
|
g_assert_cmpint(vlan_parent,
|
|
==,
|
|
nm_platform_link_get_ifindex(NM_PLATFORM_GET, PARENT_NAME));
|
|
g_assert_cmpint(vlan_id, ==, VLAN_ID);
|
|
}
|
|
|
|
/* Add again */
|
|
g_assert(!software_add(link_type, DEVICE_NAME));
|
|
|
|
/* Set ARP/NOARP */
|
|
g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_set_noarp(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
accept_signals(link_changed, 1, 2);
|
|
g_assert(nm_platform_link_set_arp(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
accept_signal(link_changed);
|
|
|
|
/* Set master option */
|
|
if (nmtstp_is_root_test()) {
|
|
switch (link_type) {
|
|
case NM_LINK_TYPE_BRIDGE:
|
|
if (nmtstp_is_sysfs_writable()) {
|
|
g_assert(nm_platform_sysctl_master_set_option(NM_PLATFORM_GET,
|
|
ifindex,
|
|
"forward_delay",
|
|
"628"));
|
|
value =
|
|
nm_platform_sysctl_master_get_option(NM_PLATFORM_GET, ifindex, "forward_delay");
|
|
g_assert_cmpstr(value, ==, "628");
|
|
g_free(value);
|
|
}
|
|
break;
|
|
case NM_LINK_TYPE_BOND:
|
|
if (nmtstp_is_sysfs_writable()) {
|
|
g_assert(nm_platform_sysctl_master_set_option(NM_PLATFORM_GET,
|
|
ifindex,
|
|
"mode",
|
|
"active-backup"));
|
|
value = nm_platform_sysctl_master_get_option(NM_PLATFORM_GET, ifindex, "mode");
|
|
/* When reading back, the output looks slightly different. */
|
|
g_assert(g_str_has_prefix(value, "active-backup"));
|
|
g_free(value);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Enslave and release */
|
|
switch (link_type) {
|
|
case NM_LINK_TYPE_BRIDGE:
|
|
case NM_LINK_TYPE_BOND:
|
|
case NM_LINK_TYPE_TEAM:
|
|
link_changed->ifindex = ifindex;
|
|
test_slave(ifindex, NM_LINK_TYPE_DUMMY, link_changed);
|
|
link_changed->ifindex = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
free_signal(link_changed);
|
|
|
|
/* Delete */
|
|
nmtstp_link_delete(NULL, -1, ifindex, DEVICE_NAME, TRUE);
|
|
accept_signal(link_removed);
|
|
|
|
/* Delete again */
|
|
g_assert(nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME) <= 0);
|
|
g_assert(!nm_platform_link_delete(NM_PLATFORM_GET, ifindex));
|
|
|
|
/* VLAN: Delete parent */
|
|
if (link_type == NM_LINK_TYPE_VLAN) {
|
|
SignalData *link_removed_parent = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_REMOVED,
|
|
link_callback,
|
|
vlan_parent);
|
|
|
|
nmtstp_link_delete(NULL, -1, vlan_parent, NULL, TRUE);
|
|
accept_signal(link_removed_parent);
|
|
free_signal(link_removed_parent);
|
|
}
|
|
|
|
/* No pending signal */
|
|
free_signal(link_added);
|
|
free_signal(link_removed);
|
|
}
|
|
|
|
static void
|
|
test_bridge(void)
|
|
{
|
|
test_software(NM_LINK_TYPE_BRIDGE, "bridge");
|
|
}
|
|
|
|
static int
|
|
_system(const char *cmd)
|
|
{
|
|
/* some gcc version really want to warn on -Werror=unused-result. Add a bogus wrapper
|
|
* function. */
|
|
return system(cmd);
|
|
}
|
|
|
|
static void
|
|
test_bond(void)
|
|
{
|
|
if (nmtstp_is_root_test() && !g_file_test("/proc/1/net/bonding", G_FILE_TEST_IS_DIR)
|
|
&& _system("modprobe --show bonding") != 0) {
|
|
g_test_skip("Skipping test for bonding: bonding module not available");
|
|
return;
|
|
}
|
|
|
|
test_software(NM_LINK_TYPE_BOND, "bond");
|
|
}
|
|
|
|
static void
|
|
test_team(void)
|
|
{
|
|
int r;
|
|
|
|
if (nmtstp_is_root_test()) {
|
|
r = nm_platform_link_team_add(NM_PLATFORM_GET, "nm-team-check", NULL);
|
|
|
|
if (r < 0) {
|
|
g_assert_cmpint(r, ==, -EOPNOTSUPP);
|
|
g_test_skip("Skipping test for teaming: team module not functioning");
|
|
return;
|
|
}
|
|
|
|
nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, "nm-team-check", FALSE);
|
|
}
|
|
|
|
test_software(NM_LINK_TYPE_TEAM, "team");
|
|
}
|
|
|
|
static void
|
|
test_vlan(void)
|
|
{
|
|
test_software(NM_LINK_TYPE_VLAN, "vlan");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_bridge_addr(void)
|
|
{
|
|
char addr[ETH_ALEN];
|
|
NMPlatformLink link;
|
|
const NMPlatformLink *plink = NULL;
|
|
|
|
nm_utils_hwaddr_aton("de:ad:be:ef:00:11", addr, sizeof(addr));
|
|
|
|
g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_bridge_add(NM_PLATFORM_GET,
|
|
DEVICE_NAME,
|
|
addr,
|
|
sizeof(addr),
|
|
0,
|
|
&nm_platform_lnk_bridge_default,
|
|
&plink)));
|
|
g_assert(plink);
|
|
link = *plink;
|
|
g_assert_cmpstr(link.name, ==, DEVICE_NAME);
|
|
|
|
g_assert_cmpint(link.l_address.len, ==, sizeof(addr));
|
|
g_assert(!memcmp(link.l_address.data, addr, sizeof(addr)));
|
|
|
|
plink = nm_platform_link_get(NM_PLATFORM_GET, link.ifindex);
|
|
g_assert(plink);
|
|
|
|
if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) {
|
|
g_assert(!nm_platform_link_get_user_ipv6ll_enabled(NM_PLATFORM_GET, link.ifindex));
|
|
g_assert_cmpint(_nm_platform_uint8_inv(plink->inet6_addr_gen_mode_inv),
|
|
==,
|
|
NM_IN6_ADDR_GEN_MODE_EUI64);
|
|
|
|
g_assert(NMTST_NM_ERR_SUCCESS(
|
|
nm_platform_link_set_user_ipv6ll_enabled(NM_PLATFORM_GET, link.ifindex, TRUE)));
|
|
g_assert(nm_platform_link_get_user_ipv6ll_enabled(NM_PLATFORM_GET, link.ifindex));
|
|
plink = nm_platform_link_get(NM_PLATFORM_GET, link.ifindex);
|
|
g_assert(plink);
|
|
g_assert_cmpint(_nm_platform_uint8_inv(plink->inet6_addr_gen_mode_inv),
|
|
==,
|
|
NM_IN6_ADDR_GEN_MODE_NONE);
|
|
|
|
g_assert(NMTST_NM_ERR_SUCCESS(
|
|
nm_platform_link_set_user_ipv6ll_enabled(NM_PLATFORM_GET, link.ifindex, FALSE)));
|
|
g_assert(!nm_platform_link_get_user_ipv6ll_enabled(NM_PLATFORM_GET, link.ifindex));
|
|
plink = nm_platform_link_get(NM_PLATFORM_GET, link.ifindex);
|
|
g_assert(plink);
|
|
g_assert_cmpint(_nm_platform_uint8_inv(plink->inet6_addr_gen_mode_inv),
|
|
==,
|
|
NM_IN6_ADDR_GEN_MODE_EUI64);
|
|
}
|
|
|
|
g_assert_cmpint(plink->l_address.len, ==, sizeof(addr));
|
|
g_assert(!memcmp(plink->l_address.data, addr, sizeof(addr)));
|
|
|
|
nmtstp_link_delete(NULL, -1, link.ifindex, link.name, TRUE);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_internal(void)
|
|
{
|
|
SignalData *link_added = add_signal_ifname(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_ADDED,
|
|
link_callback,
|
|
DEVICE_NAME);
|
|
SignalData *link_changed, *link_removed;
|
|
const char mac[6] = {0x00, 0xff, 0x11, 0xee, 0x22, 0xdd};
|
|
const char *address;
|
|
size_t addrlen;
|
|
int ifindex;
|
|
|
|
/* Check the functions for non-existent devices */
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, DEVICE_NAME));
|
|
g_assert(!nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME));
|
|
|
|
/* Add device */
|
|
g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add(NM_PLATFORM_GET, DEVICE_NAME, NULL)));
|
|
accept_signal(link_added);
|
|
|
|
/* Try to add again */
|
|
g_assert(nm_platform_link_dummy_add(NM_PLATFORM_GET, DEVICE_NAME, NULL) == -NME_PL_EXISTS);
|
|
|
|
/* Check device index, name and type */
|
|
ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME);
|
|
g_assert(ifindex > 0);
|
|
g_assert_cmpstr(nm_platform_link_get_name(NM_PLATFORM_GET, ifindex), ==, DEVICE_NAME);
|
|
g_assert_cmpint(nm_platform_link_get_type(NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_DUMMY);
|
|
g_assert_cmpstr(nm_platform_link_get_type_name(NM_PLATFORM_GET, ifindex), ==, DUMMY_TYPEDESC);
|
|
link_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_CHANGED,
|
|
link_callback,
|
|
ifindex);
|
|
link_removed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_REMOVED,
|
|
link_callback,
|
|
ifindex);
|
|
|
|
/* Up/connected */
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert(nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
accept_signals(link_changed, 1, 2);
|
|
g_assert(nm_platform_link_set_down(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
accept_signal(link_changed);
|
|
|
|
/* arp/noarp */
|
|
g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_set_arp(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
accept_signal(link_changed);
|
|
g_assert(nm_platform_link_set_noarp(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
accept_signal(link_changed);
|
|
|
|
/* Features */
|
|
g_assert(!nm_platform_link_supports_carrier_detect(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_supports_vlans(NM_PLATFORM_GET, ifindex));
|
|
|
|
/* Set MAC address */
|
|
g_assert(NMTST_NM_ERR_SUCCESS(
|
|
nm_platform_link_set_address(NM_PLATFORM_GET, ifindex, mac, sizeof(mac))));
|
|
address = nm_platform_link_get_address(NM_PLATFORM_GET, ifindex, &addrlen);
|
|
g_assert(addrlen == sizeof(mac));
|
|
g_assert(!memcmp(address, mac, addrlen));
|
|
address = nm_platform_link_get_address(NM_PLATFORM_GET, ifindex, NULL);
|
|
g_assert(!memcmp(address, mac, addrlen));
|
|
accept_signal(link_changed);
|
|
|
|
/* Set MTU */
|
|
g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_set_mtu(NM_PLATFORM_GET, ifindex, MTU)));
|
|
g_assert_cmpint(nm_platform_link_get_mtu(NM_PLATFORM_GET, ifindex), ==, MTU);
|
|
accept_signal(link_changed);
|
|
|
|
/* Delete device */
|
|
nmtstp_link_delete(NULL, -1, ifindex, DEVICE_NAME, TRUE);
|
|
accept_signal(link_removed);
|
|
|
|
/* Try to delete again */
|
|
g_assert(!nm_platform_link_delete(NM_PLATFORM_GET, ifindex));
|
|
|
|
free_signal(link_added);
|
|
free_signal(link_changed);
|
|
free_signal(link_removed);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_external(void)
|
|
{
|
|
const NMPlatformLink *pllink;
|
|
SignalData * link_added, *link_changed, *link_removed;
|
|
int ifindex;
|
|
|
|
link_added = add_signal_ifname(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_ADDED,
|
|
link_callback,
|
|
DEVICE_NAME);
|
|
|
|
nmtstp_run_command_check("ip link add %s type %s", DEVICE_NAME, "dummy");
|
|
wait_signal(link_added);
|
|
|
|
g_assert(nm_platform_link_get_by_ifname(NM_PLATFORM_GET, DEVICE_NAME));
|
|
ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME);
|
|
g_assert(ifindex > 0);
|
|
g_assert_cmpstr(nm_platform_link_get_name(NM_PLATFORM_GET, ifindex), ==, DEVICE_NAME);
|
|
g_assert_cmpint(nm_platform_link_get_type(NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_DUMMY);
|
|
g_assert_cmpstr(nm_platform_link_get_type_name(NM_PLATFORM_GET, ifindex), ==, DUMMY_TYPEDESC);
|
|
link_changed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_CHANGED,
|
|
link_callback,
|
|
ifindex);
|
|
link_removed = add_signal_ifindex(NM_PLATFORM_SIGNAL_LINK_CHANGED,
|
|
NM_PLATFORM_SIGNAL_REMOVED,
|
|
link_callback,
|
|
ifindex);
|
|
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, ifindex);
|
|
g_assert(pllink);
|
|
if (!pllink->initialized) {
|
|
/* we still lack the notification via UDEV. Expect another link changed signal. */
|
|
wait_signal(link_changed);
|
|
}
|
|
|
|
/* Up/connected/arp */
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
|
|
nmtstp_run_command_check("ip link set %s up", DEVICE_NAME);
|
|
wait_signal(link_changed);
|
|
|
|
g_assert(nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
nmtstp_run_command_check("ip link set %s down", DEVICE_NAME);
|
|
wait_signal(link_changed);
|
|
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
|
|
g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex));
|
|
|
|
nmtstp_run_command_check("ip link set %s arp on", DEVICE_NAME);
|
|
wait_signal(link_changed);
|
|
g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
nmtstp_run_command_check("ip link set %s arp off", DEVICE_NAME);
|
|
wait_signal(link_changed);
|
|
g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex));
|
|
|
|
nmtstp_run_command_check("ip link del %s", DEVICE_NAME);
|
|
wait_signal(link_removed);
|
|
accept_signals(link_changed, 0, 1);
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, DEVICE_NAME));
|
|
|
|
free_signal(link_added);
|
|
free_signal(link_changed);
|
|
free_signal(link_removed);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static guint8 *
|
|
_copy_base64(guint8 *dst, gsize dst_len, const char *base64_src)
|
|
{
|
|
g_assert(dst);
|
|
g_assert(dst_len > 0);
|
|
|
|
if (!base64_src)
|
|
memset(dst, 0, dst_len);
|
|
else {
|
|
gs_free guint8 *b = NULL;
|
|
gsize l;
|
|
|
|
b = g_base64_decode(base64_src, &l);
|
|
g_assert(b);
|
|
g_assert(l == dst_len);
|
|
|
|
memcpy(dst, b, dst_len);
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
typedef struct {
|
|
const char *pri;
|
|
const char *pub;
|
|
const char *pre;
|
|
} KeyPair;
|
|
|
|
static void
|
|
_test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode)
|
|
{
|
|
const KeyPair self_key = {"yOWEsaXFxX9/DOkQPzqB9RufZOpfSP4LZZCErP0N0Xo=",
|
|
"s6pVT2xPwktor9O5bVOSzcPqBu9uzQOUzPQHXLU2jmk="};
|
|
const KeyPair keys[100] = {
|
|
{"+BDHMh11bkheGfvlQpqt8P/H7N1sPXtVi05XraZS0E8=",
|
|
"QItu7PJadBVXFXGv55CMtVnbRHdrI6E2CGlu2N5oGx4=",
|
|
"2IvZnKTzbF1UlChznWSsEYtGbPjhYSTT41GXO6zLxvk="},
|
|
{"qGZyV2BO1nyY/FGYd6elBPirwJC9QyZwqbm2OJAgLkY=",
|
|
"v8L1FEitO0xo+wW/CVVUnALlw0zGveApSFdlITi/5lI=",
|
|
"/R2c0JmBNGJzT594NQ0mBJ2XJjxt2QUSo+ZiqeY0EQA="},
|
|
{"YDgsIb0oe+9NcxIx2r0HEEPQpRMxmRN0ALoLm9Sh40Q=",
|
|
"nFPs1HaU7uFBvE9xZCMF8oOAjzLpZ49AzDHOluY1O2E=",
|
|
"zsYED2Ef7zIHJoRBPcen+w4ktrRsLPEfYwZhWIuXfds="},
|
|
{"kHkosM503LWu43tdYXbNwVOpRrtPgd9XFqcN7k4t6G4=",
|
|
"b8e092WT+eNmnxCr5WE2QC/MXAjDagfG1g03cs2mBC0=",
|
|
"VXz0ShGWT7H0CBCg2awfatmOJF15ZtaSMPhMsp+hc3A="},
|
|
{"4C2w5CEnxH59Y2aa6CJXgLdDtWoNMS2UJounRCM1Jkk=",
|
|
"gC/R9umlnEQL+Qsz/Y64AlsdMge4ECe5/u/JHZCMWSs=",
|
|
"2bmL5ISr+V5a7l7xFJ695BLIJyBgx8xnxzybkxiRHOg="},
|
|
{"KHJSzFGkXcZf/wbH2rr99SYtGKWbL680wA2AcDE94lo=",
|
|
"BsN23h4aOi458Q3EgMQsodsWQxd9h/RxqskAUpsXfgg=",
|
|
"nK4Zv34YKEhjuexhq1SgK4oTd4MZJT5gcpYvEuPjc7Q="},
|
|
{"QGMulXJ9e3AVxtpi8+UUVqPOr/YBWvCNFVsWS9IUnUA=",
|
|
"kjVclP5Ifi6og2BBCEHKS/aa/WktArB4+ig06lYaVlg=",
|
|
"0+mmceDPcSRK3vFnYqHd9iAfY+Nyjzf/1KgDeYGlRkQ="},
|
|
{"AOJiDD4y6GA7P7gugjjQG9Cctvc5Y27fajHz6aU3gU4=",
|
|
"gEnHn6euHtcMEwZBlX6HANPeN9Of+voBDtltS38xDUw=",
|
|
"wIH1OxgX6GLxx/bnR+t3fbmjGZDTU3WMxp7t1XGezqM="},
|
|
{"COsls2BlCltaIrrq1+FU51cWddlmoPPppSeIDunOxGA=",
|
|
"+n6WuV8Tb1/iZArTrHsyNqkRHABbavBQt9Me72K2KEc=",
|
|
"t4baiprSO9ZbKD2/RutOY9cr+yCajQWZGCTnQdrFQj0="},
|
|
{"uHawQq2BRyJlsTPoCa+MfBVnv4MwtRoS+S9FEpFOEVg=",
|
|
"8lcmr27afeb6iI3BQCaDtvalF2Cl7gxRZgs+nyJ/fEg=",
|
|
"Eh9o/6W60iujBLIHuRfNrPhOWAn7PambT2JRln9iwA0="},
|
|
{"yL7hmoE/JfRGAotRzx9xOpjfrDA3BFlPEemFiQw40Wk=",
|
|
"BHK0PHi5kp7rOfQ46oc9xlVpB+pZeZYXTtH7EXr5TwU=",
|
|
"BS2h2ZZyW0BlYMmLR29xyHEcZ4jtO7rgj1jkz/EEaxU="},
|
|
{"ON8YrTHQgoC5e0mAR9FakZ8hZ/9I7ysuE21sG546J1Y=",
|
|
"Bm3l5I6iH1tDrv6EgdZU9PzHqp0H26Z6ggmmIypwxy8=",
|
|
"qKVfbCnK1EI3eC28SsL+jyBnEnIF/nRJQJzDevBFdNQ="},
|
|
{"KGLO0RI0VlQFCG+ETUqk25HdaKUnUPXKOKkTh/w8BXU=",
|
|
"sBDBwQFC7k8UMdMzuavKBkBjYYKigzvYmGF5rm6muQc=",
|
|
"BNfZF9d7540pUGGOQCh3iDxAZcPBqX4qqM00GSLPBek="},
|
|
{"KGdWyEodIn7KKI2e4EFK9tT6Bt3bNMFBRFVTKjjJm2E=",
|
|
"lrbjU/Xn9wDCZQiU8E5fY6igTSozghvo47QeVIIWaUk=",
|
|
"LczqW48MW8qDQIZYRELsz/VCzVDc5niROvk7OqrTxR0="},
|
|
{"wO3xinUGABgEmX+RJZbBbOtAmBuPPFG6oVdimvoo90w=",
|
|
"dCIvTzR6EerOOsRKnWly1a9WGzbJ4qc+6t3SSzLgWFk=",
|
|
"wFj0zpr5PadBoBy0couLuZ1qudZbXLbV/j3UT+AyKeo="},
|
|
{"+JNOBlO4tp9vvQk6UO4r3sILyEgjl+BBoWketZufyn0=",
|
|
"Q6LSv9y7YQkJEzQ/1mpjJEgOrO8GYPUTgcizjh7Cm34=",
|
|
"kg7AG9MuN04xPJ5Z0IcNZ4a8d1b/n4GsGIeyA4FaaSE="},
|
|
{"+EJcThLRwjZ+h1CNNFu15HWzznf4u/lPVw8hifTm2Ec=",
|
|
"Kkn2jFqwBzyIFQfD0OpmePFSmBYmhKagv4pGgkqsWgE=",
|
|
"jYpxojj8WKYe/XIXMP+uv1Fv0+TKrs83tqfzP0AGdcI="},
|
|
{"+DKFqSMNFmxriEFj3qatuzYeTJ9+xWYspZ4ydL3eC0Q=",
|
|
"3o37bsg6HhRg/M9+fTlLcFYc2w/Bz9rLQySvvYCKbRE=",
|
|
"Jb9qoDIBat1EexlgfpRbXa7OflptME8/zt93bldkiVE="},
|
|
{"EH3MjFOMqRoDFQz+hSlJpntWBeH3lTk6WPjTIQjr42o=",
|
|
"PbPewED/nxSBLdM7AXMj7uS3bCgAAg8M6F4iPLd0b1U=",
|
|
"pj4+UgOGkpJwlRvX5BRXZzmzAUnDtUtJsS7LzbcJWzw="},
|
|
{"kL6M2KvO+vPBLEc/a0DpEHTibQ1bwaMRT9b9SkzeP0Y=",
|
|
"pS3G2bHHlkOE6UHP0qVitDuxXgjEaZTviTjNc55RbVs=",
|
|
"ZVZpWOtYqhX3CpF1kATg/38J6pvUJo8AS1sVYjs3rUE="},
|
|
{"sFlcRLDn36fnew2Ld92IHJwnKifdS3aF1MWRPs6K3Wg=",
|
|
"OpjUOTiWExaDYULTINB4yQFqc3mnU3RjQzGRV+KtdFY=",
|
|
"of0V/uoFRNljv/XTt/tXgoquLRH93Ty0KNiaPUpEi2w="},
|
|
{"UJ8hjDsg3jfsnnfPH8Gw9FnCb6taTuviurAfZu+kEFg=",
|
|
"3byjHksUOv8CNjGGKvHvvrJDURBhCIL5UtfZbgyVWCE=",
|
|
"9f7dbWif51gGrE7R9LeuewQSrvGFGTOB3ceJC67jSkI="},
|
|
{"iFFPKGIfqeUKY/w72KAZSjd/PGTqCakHYBV10xMDfnI=",
|
|
"ehneHATNSXtsJTOiPjVSc0QARkihgcfcvoXKFWKfQnI=",
|
|
"yKdqDBcRwA7RCg4GiY/b5IsWcExPleOBde/hjxc36a4="},
|
|
{"GDGocdPJTPUAllxQo7SpXZKqMPn7lpxQELQUX9ETHmE=",
|
|
"n0ScNEou4ekfrXRRXvcADLu2Afj8g5D3TuDP/I4KrnY=",
|
|
"8QhswqAhi/ehhcmCwQF5aSh80TvIGC/gRL5jBn5wOH8="},
|
|
{"UCcrlN8fX2ZdNdhaEBNwktwL+H0ZO7fhaj7rgdUutmw=",
|
|
"LF8J728ilXs4TphnrgR6r0p7W3912DYnsXkGMEPQnRE=",
|
|
"cYfMjxl2REYir7frGeB0u+NHAaFYF02ysgpBhOL5ygc="},
|
|
{"SH0657XuIiHidVmViXZF30RUWtkuWXcWWHmKZHTiOG8=",
|
|
"7k6j49W1u5qgLE5MQUc1osPVW1oPPhzjrGvJ7o9YamY=",
|
|
"dV2+7rNk/3LR2IcwYg/c+Wvzep1yjY7/u1I+nnlTQ00="},
|
|
{"qFQWs6jzrscV42pGISQyA7JDvFFAvEQCWJi584VHD2g=",
|
|
"AT63nHKLC17yUvkR4lOVPxCr4DD3QhXmcmecOTn+Amc=",
|
|
"2Qe2fwJbFcu1CmKpktElOFkSQMqlyvlV3ZUIAd/Dcts="},
|
|
{"6J+yLxgPwWtUbk9I3zbeD8RuK6XkQjJ0wTJ1zSVhflQ=",
|
|
"NJzMBYyPZjk3eLmgdKaOeWyNER5YZF1mR8Umeiu9f28=",
|
|
"pp+4+XHw5ZmHGJ7WbZ1xLYRsnTI17QIbb0bzHzYZrBs="},
|
|
{"KJGoWYNVDUWcEMg+E4tljv1LiWAbdRw2QVapYqdFa1Y=",
|
|
"M2SGk9WVnzYNGnT777G/JE8uUsY2f7mszTwlue73UDE=",
|
|
"Jg8N7GbhbYB400foFP+OH0v+hCaL1jW61bajSA6EZqc="},
|
|
{"uAgrgppPyIvk8S1CHUmaCaORsgFFfBreB8pxXmbSdXw=",
|
|
"dJ22bER4fD3qF2/yIGWQ7SgmZ990sy/SbANjmUMkzws=",
|
|
"mKkd0OoAR9sClmD+k3fL9weBsoCy5GQGz9BP0kAQIjc="},
|
|
{"EI3Q8gePNPrtFyoMcv7hOihQgroF/dfjzPn8yvpGPWQ=",
|
|
"Y9QhJFeiyuuIZNPU56B6U//ZK+XTTe4EP7h/p3Q+dE8=",
|
|
"qBVUYw9rTWaxn55nUd55NpCWtxOUSWLt4WJGusiDS8Q="},
|
|
{"oEQvdRm/yHkx+JvlhHGT5RUFrFEUleKb9DCT55EqZ30=",
|
|
"8hsh/UHwWADTHntOJq4dy0o7ahcNAAlo2rDpjzzrVXk=",
|
|
"/GF2inW2mPtA26IgFdgOEBbBEerT740wWuP/8NyANdc="},
|
|
{"6OWrGKZKNsgfRezSUw29EnHymcgKyEKvX5/pZQlLmWs=",
|
|
"oaJeO6YSS2dodNEf97DvgWrYnFFelG5daEdN84jVVGw=",
|
|
"T5wvTdyVxK0LY96kouLjs06oUfhGChfty8OUL1Mddro="},
|
|
{"mPmzQbh2R+r1DC5hSquzKM1SDrxUdfnBPRPJrpqrgkE=",
|
|
"BtUHAnYWjDjBI42qBf9dJqezTUikYsF96o6PKEWPrVo=",
|
|
"MxU8EMmq+vVHpuK/AkFZrZDF2b+VbSqukZLPbNsCcgo="},
|
|
{"8GVxuoo1Veyr+nqxr5Q4vmsMf5qfiXwSlQ4q3+BU60g=",
|
|
"uSOLe/E9/OjIgUOk0NMBHB45E0+q4Rd+IUO2UOxmKlM=",
|
|
"+30F+56OE0Sr3wY2clKw4kgE+2XiucMg7xjK6EemXuk="},
|
|
{"qORPKb+qFuU/9TpFbRUupHsqm9iyk9pa6cpik+EVDkg=",
|
|
"bMZxxd+Z9I0XA1h9U8JEY+/mRxWGnvbXDZ5Dxz7YzS0=",
|
|
"SmkkqOz4OhHuSL6cxuRm9+Mlt50Sfd0sMDFTC78gqOE="},
|
|
{"2Ko3IYhXKcdOMIJGNpASk9saNSZsI64lyJPOoxpQ2kI=",
|
|
"xVOc9PxY1VFaZfemmKi+Ei2liHhmeTu+JMa+rS00gnA=",
|
|
"+398DlW8kWeI2aRaC4QfcrEjwqPKCohyDeWdaI1wvv0="},
|
|
{"CPioGCVpxnym62nH/QoCt1RiiaaxUcuFjvh5kRhjqHA=",
|
|
"W0XxlBLrZgFKhggMvvv6oFf/RJbfs92qv8JK9e+5i2o=",
|
|
"bsK2U6CRAUv1uVgYQ7NpqjWWswFIDiDPDEtU1XQygSA="},
|
|
{"AF17siKaeiO85hikYN0IWCMGWqPm1UOoCkXMltJGUVk=",
|
|
"B+PFos9aN2S5bLxzGZHljRZj41j3rIx8RWu0vDUzq1w=",
|
|
"Qb8d6iDYv3m1h7PE8j0Exl2cSwpHkim/fJ1S4P7MYvY="},
|
|
{"wMFDBTJzx5tDCBhMkrptYJ8w9EeURjc4xeDQpevxAWo=",
|
|
"4ec439EXE5WQzvtV9reSX+aMmdq5k7o9Ayt8oQp+RhQ=",
|
|
"jwQlvdNH5WtSSU10H+fh/JisOlaBaohDPEp/BYnTt1Q="},
|
|
{"4GaJpIFigNDwd31O84pLIMM/o2qhp0ydlI/ydD/2a2Q=",
|
|
"r/LdkCoK5/BPGdq2+XJO8sCRhI+8ULFmg0887V43PAI=",
|
|
"Da+3ZZvEJdx4TYFMIDUlbkmytILnSTNxTKX+sQdjMd4="},
|
|
{"gMnojGqCLmMfGp2m31xlKZ/rIV2b8ockw9DPahRyu0c=",
|
|
"H6tKCTosnM4BXKqflXrkTdJyNlCIZhQ3ZRxfrvSdrDk=",
|
|
"4Z6K3LKIMV89plcjMb9CzSzJl03SWRe/++geBMZcOtY="},
|
|
{"wKCg22aNNoHnDJ0oAKE46FcSSsREW4AaGn5WxCSeXUs=",
|
|
"9NDTFC0iPt4HbbWepLHhN5poNTN2fdxJKNadsNT7qzY=",
|
|
"GSVTOCnfLpJ1VCOLHaKSjCMv7/OlcnQiP5+5woqkud8="},
|
|
{"oCoykq7pcJcg2X2V5TBRzGwn8hzzHC05WUreuotdznY=",
|
|
"DxfwnbMqr5Wn5SAyFolfEmNQT6l84Oq69ngpg6H6Iio=",
|
|
"p1RHBuqhuDa1MAQ2lbqmUQFu0CTwYlf73fWZSj9tQhA="},
|
|
{"UO7YVyRUVkcKr7c63VWWV2zj36XD3HyDfLZCqvrZmFc=",
|
|
"360lzYtIyHq5lv/QXSCe4bL4G2J1jBXFJ8yS+Ycr7Bc=",
|
|
"RRPQ1XWF1HN8Us4dtfn2eemdjgtWm7U8r7mM3y00NOk="},
|
|
{"eCGFYV/NuGP4H552E8Of1xU+3IvZxGyX+p5UFGW8iHI=",
|
|
"LqhZ4AS9dQ/MhsQnE5Oy7Q8INXY+P+mrfGY5dtg9SlE=",
|
|
"SICfqs8T5wP6IzATDCT4ovamBKPdkZ7JP4Cfsb3izec="},
|
|
{"oI3HBZknoIMMZw1BuYMkTBylt25reX7AbCqtWQv8cno=",
|
|
"B7dUgLgvQhi0RGmvaMrmf26WdjEVrhaiBclVkCKd4AA=",
|
|
"5O9K9pLXwxFAt5lfMWh4qGbwX1BM7sz0QGYxAnR77dk="},
|
|
{"sBfYn14EFVIS2M/E1aahP7mOmRNbNtyDChDMS1s6aGs=",
|
|
"FLYv0ZvzxMkc9A7OzhC4P1ZRu1aKIQd7u6gqfdekC3c=",
|
|
"kaYLcNCXnCLgiB8fleMQuboUJsj5u3YAmXL9x3ywV0M="},
|
|
{"qFwZESU/XYZXUtxwrGsFU9qPAFTzjm7EhTS1Q6ajGlM=",
|
|
"hraQQaqJCkS2yQXv+ccMOVh9V9a/qgSZJgdMAhrt8ms=",
|
|
"72oDfnWOn39gdk/ncw8Lv267I0I+m73SwxrpYojpWYk="},
|
|
{"YHhp6Zf/miuc2QXeI2lTezy0lL0pTv2b+nWNkmjYQWI=",
|
|
"UhNO5arLzF0WlZSgNOx7+IjWN+GSxDdQxZRp8uIwsyI=",
|
|
"1Q39Nzv2NGI9zWKWMpYLURAMZUg+FP+OboHHzFU8Anc="},
|
|
{"mLBBXKaCJ+7qeBZpS3wxGi/SQ4kLzun+K+QwwdwfJVQ=",
|
|
"gIq/nh7NwCJ36MvRnyrWHaRWu8lTmwfN2NvsjVl6SXQ=",
|
|
"AahcNR91GDyJBIP+vC8ZuIV8ukqjSGtd8s+cmjVC2Ao="},
|
|
{"OJG4LZlNNngFtAEQdbVVWVm6QAjOOauGcMZGbQrb40M=",
|
|
"pFHAC6HaWAOtvTRRVfSHvzG05mp4SJZXKsN/tkSF0kM=",
|
|
"IoXT3wIqWNxQhYuHWl12ODq/P7RM9LwaqglhmjKg+0g="},
|
|
{"OOwBFOQNhepiqDf04DehQLh1gpBNOluDF1ia752Yfng=",
|
|
"u715uJ/XhdjXjThCTJ9w6zzXnIhp3VCxhtso1wk+oBQ=",
|
|
"5x1Ip3Ym0KzDjGhiYjmpeWWr+dgrZlYwfr02GngPOTM="},
|
|
{"eNPFnwkQy1qw+IjFAlrDA6+sIsxbWDlzbNSsBW8R1UA=",
|
|
"OaOXaAfPb1MRpWadawFje8YZ0oxJgdCIDIP8c5X+r1U=",
|
|
"NtfaRRD0GqujnaQQoNoBbtovgO4dfVwEmEQx/YgnDpw="},
|
|
{"OLdaZItbtxH3mGqItkibIJp7KV27FrQavjhd5zq6s3Q=",
|
|
"SLSmAYxkMCGj0DO35cMLkC3NVAqK2VmVFndbOZEdA24=",
|
|
"SnBO68XQTDjxYbmYaAeEHgLwD2u4D+BPT86raRuUQZM="},
|
|
{"UBQOEz08izwr4eEK/SnQUpkt+TxCjo6Sya/XOGMLOE0=",
|
|
"wQwrwezI9LzKevGsJJCBHDG8noR0yIEtOK5Rig97SSo=",
|
|
"DpyS+0d7lrlFWkztsniG2v/j44vcuvWz3sPeghRyb5A="},
|
|
{"mN98iuqUKh67ggUdq9ZIQNZCZM90fgycTVqYKEo+DkY=",
|
|
"GYdXVW1jpS0dN1q9zMehubP7LfYqs34kszN0bXQqxxA=",
|
|
"AJPIHffB4uvvJJki4xCG0VORVBbF6bc2mZQqUx+idPc="},
|
|
{"OEd/1it8C3o+NOWxDI3DfLMXVBHJQg15N3E8F8d99l8=",
|
|
"QL1NcuUkoXxDy7M9VjGslCejcUlnUDHRghFVnr+8fmA=",
|
|
"nven9Dicl8U6QXuDO8rRNtjd4NYaa90SU+Gmv435XKY="},
|
|
{"AFMCGDu2oAP68miucsi4fmYX2KeRZnsEGv8tQm8JEng=",
|
|
"1sNxvk8uZhFsBUgxOXmuCMjDAgBbjVeWe9oaFk5Osy0=",
|
|
"t5iI5XXd56S5q0Y9HC91gzgF9uGjL9FIy6NUaKqkydo="},
|
|
{"CIAwfJghQHHr4YlztN9at6/iWkrEVCGFAxNVuQCuT3I=",
|
|
"zpUOF1h17g7RpBzrVlN7oTRz6e+dxcDL8OsAtHwgLC8=",
|
|
"kOSwC1p6Uoti9E9Eg7ViPZwCytuvp5Fr5Buw677aogU="},
|
|
{"sC8vrAVBU0zvhWDRfzfySjvopXm2/cTMkTLmioyO3Es=",
|
|
"p6H7GWm8NfgyO5OCX/COjvVT4MAnTs9ZUj4uZMK8XHA=",
|
|
"9Tzqo57V/h7+6nSNAHSBKdmU7ultlvZbAnNKSRlrLi4="},
|
|
{"eI63gjxCZGnzqZxPEi/ifYphXhxIRI2ZxK8jzqo3mmU=",
|
|
"XyNzEuU9x37fxFCnrZH89Krs5/UqGVx5wNkGfQCAYz0=",
|
|
"vZ2fTlRPnJQ+q33YdS5p1aweqPGj/kTMc4Uq80FtFjI="},
|
|
{"aNJlGtm79/RS4SQ/PC4YM6LFo9zAqDr2/RjLqk/z/1A=",
|
|
"lgZ9akPrABmfHQMlfNFnnpAJzGtcsaU9mUjEYKfzZHc=",
|
|
"d0Xt1Bcgphd1HMI0RneA4VdBbMZL1qNGJAvFhb080eA="},
|
|
{"oONSnHirNh3cuH93Ty0C9AXKebGY+cdF3R0DtPzIQlo=",
|
|
"TuREKfA8EVQiYWsPx8veUzjN2cz/b72limSLWlrCWxw=",
|
|
"vEqqKbpZf0EM6EApMUaUH65r3Zr81Y/DSODhE4H7U3Y="},
|
|
{"+D6RyLEaHJ9YF9WDyOlwh87KaNJcc6lqX8Arp6yqHF0=",
|
|
"EpecjfIo1/EEbmsgUtzEDqLu2ut+SMmzqaBL9Z/MlCA=",
|
|
"oYfO6/7XQgEYT9zmr4sqFrk0muK/fEv3FfD8MzZzjkE="},
|
|
{"OCmW5KQql2PRMJnsMYQjXlr6TSYUbxJBknqZtXJPSHM=",
|
|
"ZZR2ghHlCwAJu/XlsEZuNS6XiGPwuXzyMPPywYFapVM=",
|
|
"fqSCXq+pKJJ6yNvlOi+tyQ9E4Y6kc4kblGrVqN2WuXA="},
|
|
{"APWXDAe8d2ia1CUbf/IzSPXOUjR8TVuJgmISiWw0/EY=",
|
|
"jrT5P5YCkG+U7cfNTvCKy0GSEgsjwmJtHg+8HBP6ZCA=",
|
|
"t75aUjZXMPir8Ao0yhVClh9/BdWxSL+11CjK3iELNWk="},
|
|
{"8Nw4sRis7M/6Om+3w5YHXthyMzLGuP48teqdzbHNPlA=",
|
|
"lj3q3ZYij3ZJ/QunK8n9I00cv/Z+O1TU1kFFl8x3DTE=",
|
|
"adqB79P7gbXEYYnSd1/UPCwFffTAPXa9kHWynRBYcGo="},
|
|
{"yOupps5XbjV0fIZKnGhrpcxB7yDQzbBILC0UMJyVS1c=",
|
|
"+MDV/t9UCIdgm3IkH3BZlxaRPJ3lejRmrm4UPApq4mk=",
|
|
"AOJPmQxsU6hjOd+9mHnF0VL7Afih3P1Fr625xFT4FtY="},
|
|
{"cD2DEl4MBwONuTV0db5XreoVjQAUZFNXqIeFEU3KFkE=",
|
|
"2CeHrjN7tBX48k4Sgv5fIHG06e57q/ucCL+8DIRmfXw=",
|
|
"3EUo6MRzs6rSoY/7AFs8wiBiTXPcHzerLh6Xp3aMGKo="},
|
|
{"EA+S3a9ZeOLiRbhTxaT2wkpyDheAmai+UJa6SFGzSm8=",
|
|
"GGByUKZx/FPa2OkJoqVTHXx+6jrIpIw5rf0rp43MHko=",
|
|
"BXoDA3yn0JcMV7hHVzEqhlwAORvhToFO1qG00nas92A="},
|
|
{"eBeJi/imBiV52WEqrwAprUQggqdQmvTTmWtLq8pDDkM=",
|
|
"zCX26ZTOZHLpq5x5aIUL1XhIVoXJLp/zcXwnmFA3jBo=",
|
|
"Dm/DCxXWYXEsmQgxAD3KREK2PF0bUSnV5WRAaya8s1I="},
|
|
{"8C7p+EQO+CnWUSjHVu3PpeWpUIbLy48zpftZu021plM=",
|
|
"DxpnF/IbKAh6kmWC5Jpj8iw387EDkrvjsjOb9fbTSng=",
|
|
"bGrk0OshJB+0oQOK0QGKU8+lotnIDz3oeUnMZGienyM="},
|
|
{"COIez7YcBJiOJCLxxWV5UGLW5/o009YI0aszlD/PiUc=",
|
|
"eD9USWV37LFIOxlDSHyOmfFqNJFpORRlzEI+HoF/czI=",
|
|
"n+/ra86gUSF2pNZS51nt2JgrzXnQJl+dWswOq/Ahs94="},
|
|
{"iBBSTG9VLC+T9+ahNaQ4umZoig8o7w1DaeOw+cD2BGc=",
|
|
"XnAxqDlvGnQ6aakv8ABGHVj07qVQfk4NChZbstTMBxg=",
|
|
"7KKSwu/4yWr1UzFmNMGtiaSwdYMhP/HKbrQLlABL4UE="},
|
|
{"eNmwattflehr9+KsVqTuwt1YaAc5ONkaIaTQt9Gkhn8=",
|
|
"1NNVvm++YTTGMKyAXfGOCZ4aDDdFFH5Um3vAg4XimDo=",
|
|
"bXNrnDTP0pBay9ytZe7xpiKoSi12F7WUXqoIeI++Xvo="},
|
|
{"QJotpmZINx9eptKpkh9j3JlEDcHdWnjEbicdBS7gPXM=",
|
|
"3gLYKeoruVZ/AYjym0gciDvRHj45UIWyHhNjWj2Wj28=",
|
|
"NwuUkkE5yOWT7wed7bltgAk71miz3cSooiIDAdv6kKw="},
|
|
{"OAYGuxH70OPQvhVIX4BhSCWUyzAI5H2IkYxKgC/AO0M=",
|
|
"Rj9iNF/FagkXfdLPqc9LHfaoGR8GlvY3gun2FilE508=",
|
|
"hkNXLVMlBRsMEaQKkSzevcEK2sMu0AShGKQJMNqdzWM="},
|
|
{"uBrgZ7wLHrOV/0dNiEqo7FjY9VnJqL5eUDHJWAc9QXg=",
|
|
"3Hnln8ZHfSaK4OzESJe5U6NcLaW56wzfZICzvzefnSo=",
|
|
"DhXsehe5FAmbUidXT5ZpZIAuu1eF9rkU6cF3FBoKwOE="},
|
|
{"sJknn3CHvx/812EWU3ddLdLLZFBKsc+wx35GXyiRsHY=",
|
|
"qqa2dNSt0jWozGyqpokP392H5/DOAUUZmUpyZDaUEEE=",
|
|
"1Dyz8CvmF17oKT/wG2fu3vRzPzgQv8/OY9GJYew4FG8="},
|
|
{"yOumS9HN68ZwIm+5hZol3jFQ0DB4SKuW/ld3y8wioGk=",
|
|
"6PowsbKj/fKSzXZMAfaSkP3fE+4AThL9xm6ysQzMDxg=",
|
|
"vF8cKu9X9FxgCjyVZ5RG7nuue8RelF5Qsb8Efme4M4A="},
|
|
{"mISm5vQfPdK72SsaHh6O1/ARvaWCtm+KZNcpTsyt500=",
|
|
"YCORDQDpb1U8vADdstBgXkg0N7QaAc5VoXJ4QFuA/UY=",
|
|
"JlrBmfaCgbfEVD9YQq3c03WwwsHWc1nBwp1JkFORC3A="},
|
|
{"cPyu3Qry6qbsiOJKFGRziZ9LJWJ47k3ZSXiGkQXuQm0=",
|
|
"/cmBZTbqEp8sababPAxGb3OvDAEE7MlwPOwEFHE+7yM=",
|
|
"lp0Hhc/rVtpT5FtLLccChqDl3El48XtP6Wm6JwjI7jo="},
|
|
{"YKsMYU0SINbPwWw4RDCJV6GnzDlSp1ZNwUw2euGWi0A=",
|
|
"/KmBReATQbFnLg8YKV0jwhqKeishRoWvlVtMX3550Vk=",
|
|
"7fXpPSMo1Fw2sOXtjTtvFU+DbZvS/FWB9wAsywWx6R4="},
|
|
{"WD0YI3y71eIp/GXw9i+7scEiQKSBkGihZWE+s6fGmWo=",
|
|
"RdthAL/qPnAZFb3xBgRMiAtGHNjgokzoKX9iO2K5qhc=",
|
|
"4dk4HGkT9dBmomGNorDE/hLr/HEFhljtl4zz3M4sG58="},
|
|
{"oD8KWhJYZVhutJRb0kZlZnB22QUXzi2FfPRD0ll65UM=",
|
|
"MYTBGHh4Ukj97pKj6qcfWmxGNQzmU3/aBOX2f1tfhG0=",
|
|
"VT1gC+a9nRJzYMi/TPvRVnn3IQlaop/jKmmxZePEME0="},
|
|
{"0Ns/1SOiqR2CpHRG03QNzJJd5gxTm1XJmSkFlugjQ3k=",
|
|
"KvQAI+ekNOa2xfEvfyc9JGcS+CTUrnnhsKrlyJGJixg=",
|
|
"J8LmSX6zElX3S9q4PNvh2NKUtAiQ3oHiYjSJ7yErPlY="},
|
|
{"mD6TeF4ezSPXN/csN1OhoAREFSXllI+zl4DUOInVq2Q=",
|
|
"WmLJ9ep2EqFcSftnYFJsmWyUxqL0zzuSzVEv94PcISM=",
|
|
"U2+ILy2NDmmfgSW78C8dl8GyHESUc1lXPHPpg5F+gr8="},
|
|
{"SMJoXOYgHz8HSzY+ByeWLcSP5qFwv7YjRe0bcKesRnM=",
|
|
"DEsNSOY3TEs9J2YgqroQ4xKq8T8xNJQjvvE4UrTItQw=",
|
|
"Bws1Hk2+lO+JQ7ME16EbwAdsBkWsGvti0Gb6LY2Lrms="},
|
|
{"iGhXF0Hg0tqZmpwAMiolxvbvTPClQ7LlBAspSSyFEHE=",
|
|
"7Xxzpwl7yRWehHNWTYVtFkdChJdXhtY4Mtw1fA9QcCg=",
|
|
"Swjfv0PjuaE8Oq3a17BVno5I+q49dZlPwKK1bPUoKNI="},
|
|
{"MIazjx3qTi6Qz3WzhtCPw3i4Q2uZBHcuMoh++ZGFYUk=",
|
|
"oni8pbFqk9Ya+Fx+911Nl1SN0FD/hR1jwb2RH3t/pRk=",
|
|
"ZYAFcj67LkbNURYbSnCCWGxAG8QLDGWwbl968mA6ZA4="},
|
|
{"MAadYdiFM2cPuJF19q20Yoo5KJabuR9TUQ9jG5nvA1w=",
|
|
"5OcE8XV+UPoBVbgqBQdVF62GZCW9DOQEdxrQsktPPBA=",
|
|
"FCZsEFXouy+xtxv8X7VroXtvPG1Z1HFHL724tz1jcUI="},
|
|
{"+GwxMmD2dee5+QmvXNI0NdP+rNWoSXTN42otbp0aZ24=",
|
|
"Y0N44baz9ihclCUnv6rRbDqCYu4BxQlBfNnTz3NNe2A=",
|
|
"/LqSgkVQNkQ/oBiZSgpM9Rw7BJv0RvRpEQpvlizvHy0="},
|
|
{"8FREpCtncOcT7+W2nW4aYSjmSbADtVSH9rIliQZZUH4=",
|
|
"fTNSd0JeREhXmPfjrmrAu6Lu/yHkB9GyxR3SyO4kZ28=",
|
|
"262KN/iG/iJEaZeerFm1yVtvhFVGgQFwSvtxTcjZzeg="},
|
|
{"EDhaRQGtscjoSE9wJOnSXoQVtVruIqyzknty+x/vDWo=",
|
|
"eMmMgws6ZxDIxZ6QSwGjZO1Mx/r5T+fJjSTKGMBk/BU=",
|
|
"0CyaJV6AG9bZ0C4yeZ/RDsOs9BdNqZpUxAsD30WmJO4="},
|
|
{"CJV0UB2YdvVDG1cs4oiJgHAS+f1FocGr/vGCfiovsWQ=",
|
|
"9/O9GWZEOXVm7On8lftL27PffRORju8OKl6gZd/74CA=",
|
|
"A+kXRVNOwIrA5DUa+3v7dpRC+Gbxm23LTiYmOUAXUyY="},
|
|
{"gCjDsJUwZGA7BjYVoCQsvdIgN9Q4lBHlSyKwUrl751A=",
|
|
"HRwS8T9y2qPYk7JVU/8Y+6cS+Bk8XCLCXxwN/ttbQiI=",
|
|
"iFotjA6rhUfkDv4S/wspJgEWunEmrlGSGsXcJ0+8laQ="},
|
|
{"6N5pL4gsuK+shHpDxirTnAGdyKXIlYHyfIhtB0njJGA=",
|
|
"CVZvW7NaN2XMEEKHodghBA9hLCwee/jrmttiWh/CmEg=",
|
|
"OpPEd3Sp8r6KdjNDTN4bVHETlGJ92BCK74FCdEaDe9g="},
|
|
{"UIPPTUdvhlg8qEDv6JRxM4/8F5ORjJz4ud82QZrgeEY=",
|
|
"7Nd13z5EpB3ChytvQC1CxvDY7n0H8r2Y7lzLEY8hdEk=",
|
|
"b22PvgU0M2QfNC7ZGN+RXNe5fjOzMsY32IcHTwLNIqw="},
|
|
{"oBn53Q5fmxKX02PgI6F47Rb+XoLeFQO07ok2tYhk0lE=",
|
|
"e0gtPDKXCZSoNW1uHqBPQXLfiYgyeqPMU2zZJgPXACI=",
|
|
"wmjW2wDT2EzFkyaGui7YWNLTRu8Q4eD/GVKM2utZkEs="},
|
|
};
|
|
gs_unref_ptrarray GPtrArray *allowed_ips_keep_alive = NULL;
|
|
gs_unref_array GArray *peers = NULL;
|
|
NMPlatformLnkWireGuard lnk_wireguard;
|
|
int r;
|
|
guint i;
|
|
|
|
allowed_ips_keep_alive = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
peers = g_array_new(FALSE, TRUE, sizeof(NMPWireGuardPeer));
|
|
|
|
lnk_wireguard = (NMPlatformLnkWireGuard){
|
|
.listen_port = 50754,
|
|
.fwmark = 0x1102,
|
|
};
|
|
_copy_base64(lnk_wireguard.private_key, sizeof(lnk_wireguard.private_key), self_key.pri);
|
|
_copy_base64(lnk_wireguard.public_key, sizeof(lnk_wireguard.public_key), self_key.pub);
|
|
|
|
if (test_mode == 0) {
|
|
/* no peers. */
|
|
} else if (NM_IN_SET(test_mode, 1, 2)) {
|
|
guint num_peers = (test_mode == 1) ? 1 : G_N_ELEMENTS(keys);
|
|
|
|
for (i = 0; i < num_peers; i++) {
|
|
NMPWireGuardPeer peer;
|
|
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
|
|
NMSockAddrUnion endpoint;
|
|
guint i_allowed_ips, n_allowed_ips;
|
|
NMPWireGuardAllowedIP *allowed_ips;
|
|
|
|
if ((i % 2) == 1) {
|
|
endpoint = (NMSockAddrUnion){
|
|
.in =
|
|
{
|
|
.sin_family = AF_INET,
|
|
.sin_addr.s_addr =
|
|
nmtst_inet4_from_string(nm_sprintf_buf(s_addr, "192.168.7.%d", i)),
|
|
.sin_port = htons(14000 + i),
|
|
},
|
|
};
|
|
} else {
|
|
endpoint = (NMSockAddrUnion){
|
|
.in6 =
|
|
{
|
|
.sin6_family = AF_INET6,
|
|
.sin6_addr = *nmtst_inet6_from_string(
|
|
nm_sprintf_buf(s_addr, "a:b:c:e::1:%d", i)),
|
|
.sin6_port = htons(16000 + i),
|
|
},
|
|
};
|
|
}
|
|
|
|
if (test_mode == 1)
|
|
n_allowed_ips = 1;
|
|
else
|
|
n_allowed_ips = i % 10;
|
|
allowed_ips = g_new0(NMPWireGuardAllowedIP, n_allowed_ips);
|
|
g_ptr_array_add(allowed_ips_keep_alive, allowed_ips);
|
|
for (i_allowed_ips = 0; i_allowed_ips < n_allowed_ips; i_allowed_ips++) {
|
|
NMPWireGuardAllowedIP *aip = &allowed_ips[i_allowed_ips];
|
|
|
|
aip->family = (i_allowed_ips % 2) ? AF_INET : AF_INET6;
|
|
if (aip->family == AF_INET) {
|
|
aip->addr.addr4 = nmtst_inet4_from_string(
|
|
nm_sprintf_buf(s_addr, "10.%u.%u.0", i, i_allowed_ips));
|
|
aip->mask = 32 - (i_allowed_ips % 8);
|
|
} else {
|
|
aip->addr.addr6 = *nmtst_inet6_from_string(
|
|
nm_sprintf_buf(s_addr, "a:d:f:%02x:%02x::", i, i_allowed_ips));
|
|
aip->mask = 128 - (i_allowed_ips % 10);
|
|
}
|
|
}
|
|
|
|
peer = (NMPWireGuardPeer){
|
|
.persistent_keepalive_interval = 60 + i,
|
|
.endpoint = endpoint,
|
|
.allowed_ips = n_allowed_ips > 0 ? allowed_ips : NULL,
|
|
.allowed_ips_len = n_allowed_ips,
|
|
};
|
|
_copy_base64(peer.public_key, sizeof(peer.public_key), keys[i].pub);
|
|
_copy_base64(peer.preshared_key,
|
|
sizeof(peer.preshared_key),
|
|
(i % 3) ? NULL : keys[i].pre);
|
|
|
|
g_array_append_val(peers, peer);
|
|
}
|
|
} else
|
|
g_assert_not_reached();
|
|
|
|
r = nm_platform_link_wireguard_change(platform,
|
|
ifindex,
|
|
&lnk_wireguard,
|
|
(const NMPWireGuardPeer *) peers->data,
|
|
NULL,
|
|
peers->len,
|
|
NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY
|
|
| NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT
|
|
| NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK
|
|
| NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS);
|
|
g_assert(NMTST_NM_ERR_SUCCESS(r));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
typedef struct {
|
|
NMLinkType link_type;
|
|
int test_mode;
|
|
gboolean external_command;
|
|
} TestAddSoftwareDetectData;
|
|
|
|
static void
|
|
test_software_detect(gconstpointer user_data)
|
|
{
|
|
const TestAddSoftwareDetectData *test_data = user_data;
|
|
int ifindex, ifindex_parent;
|
|
const NMPlatformLink * plink;
|
|
const NMPObject * lnk;
|
|
int r;
|
|
guint i_step;
|
|
const gboolean ext = test_data->external_command;
|
|
NMPlatformLnkBridge lnk_bridge = {};
|
|
NMPlatformLnkTun lnk_tun;
|
|
NMPlatformLnkGre lnk_gre = {};
|
|
nm_auto_close int tun_fd = -1;
|
|
|
|
nmtstp_run_command_check("ip link add %s type dummy", PARENT_NAME);
|
|
ifindex_parent =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
|
|
|
|
switch (test_data->link_type) {
|
|
case NM_LINK_TYPE_BRIDGE:
|
|
|
|
lnk_bridge.forward_delay = 1560;
|
|
lnk_bridge.hello_time = 150;
|
|
lnk_bridge.max_age = 2100;
|
|
lnk_bridge.ageing_time = 2200;
|
|
lnk_bridge.stp_state = TRUE;
|
|
lnk_bridge.priority = 22;
|
|
lnk_bridge.vlan_protocol = 0x8100;
|
|
lnk_bridge.vlan_stats_enabled =
|
|
nmtstp_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED)
|
|
? TRUE
|
|
: FALSE;
|
|
lnk_bridge.group_fwd_mask = 8;
|
|
lnk_bridge.group_addr = (NMEtherAddr){{0x01, 0x80, 0xC2, 0x00, 0x00, 0x08}};
|
|
lnk_bridge.mcast_snooping = TRUE;
|
|
lnk_bridge.mcast_router = 1;
|
|
lnk_bridge.mcast_query_use_ifaddr = TRUE;
|
|
lnk_bridge.mcast_querier = TRUE;
|
|
lnk_bridge.mcast_hash_max = 1024;
|
|
lnk_bridge.mcast_last_member_count = 2;
|
|
lnk_bridge.mcast_startup_query_count = 3;
|
|
lnk_bridge.mcast_last_member_interval = 5000;
|
|
lnk_bridge.mcast_membership_interval = 25000;
|
|
lnk_bridge.mcast_querier_interval = 26000;
|
|
lnk_bridge.mcast_query_interval = 12000;
|
|
lnk_bridge.mcast_query_response_interval = 5200;
|
|
lnk_bridge.mcast_startup_query_interval = 3000;
|
|
|
|
if (!nmtstp_link_bridge_add(NULL, ext, DEVICE_NAME, &lnk_bridge))
|
|
g_error("Failed adding Bridge interface");
|
|
break;
|
|
|
|
case NM_LINK_TYPE_GRE:
|
|
{
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
lnk_gre.local = nmtst_inet4_from_string("192.168.233.204");
|
|
lnk_gre.remote = nmtst_inet4_from_string("172.168.10.25");
|
|
lnk_gre.parent_ifindex = ifindex_parent;
|
|
lnk_gre.ttl = 174;
|
|
lnk_gre.tos = 37;
|
|
lnk_gre.path_mtu_discovery = TRUE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "gre0")) {
|
|
/* Seems that the ip_gre module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0;
|
|
}
|
|
|
|
if (!nmtstp_link_gre_add(NULL, ext, DEVICE_NAME, &lnk_gre)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip(
|
|
"Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding GRE tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_GRETAP:
|
|
{
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
lnk_gre.local = nmtst_inet4_from_string("192.168.1.133");
|
|
lnk_gre.remote = nmtst_inet4_from_string("172.168.101.2");
|
|
lnk_gre.parent_ifindex = ifindex_parent;
|
|
lnk_gre.ttl = 39;
|
|
lnk_gre.tos = 12;
|
|
lnk_gre.path_mtu_discovery = FALSE;
|
|
lnk_gre.is_tap = TRUE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "gretap0")) {
|
|
/* Seems that the ip_gre module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0;
|
|
}
|
|
|
|
if (!nmtstp_link_gre_add(NULL, ext, DEVICE_NAME, &lnk_gre)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip("Cannot create gretap tunnel because of missing ip_gre module "
|
|
"(modprobe ip_gre)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding GRETAP tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IPIP:
|
|
{
|
|
NMPlatformLnkIpIp lnk_ipip = {};
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "tunl0")) {
|
|
/* Seems that the ipip module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ipip", NULL) != 0;
|
|
}
|
|
|
|
lnk_ipip.local = nmtst_inet4_from_string("1.2.3.4");
|
|
lnk_ipip.remote = nmtst_inet4_from_string("5.6.7.8");
|
|
lnk_ipip.parent_ifindex = ifindex_parent;
|
|
lnk_ipip.tos = 32;
|
|
lnk_ipip.path_mtu_discovery = FALSE;
|
|
|
|
if (!nmtstp_link_ipip_add(NULL, ext, DEVICE_NAME, &lnk_ipip)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip(
|
|
"Cannot create ipip tunnel because of missing ipip module (modprobe ipip)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding IPIP tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IP6TNL:
|
|
{
|
|
NMPlatformLnkIp6Tnl lnk_ip6tnl = {};
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6tnl0")) {
|
|
/* Seems that the ip6_tunnel module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip6_tunnel", NULL) != 0;
|
|
}
|
|
|
|
switch (test_data->test_mode) {
|
|
case 0:
|
|
lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::15");
|
|
lnk_ip6tnl.remote = *nmtst_inet6_from_string("fd01::16");
|
|
lnk_ip6tnl.parent_ifindex = ifindex_parent;
|
|
lnk_ip6tnl.tclass = 20;
|
|
lnk_ip6tnl.encap_limit = 6;
|
|
lnk_ip6tnl.flow_label = 1337;
|
|
lnk_ip6tnl.proto = IPPROTO_IPV6;
|
|
break;
|
|
case 1:
|
|
lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::17");
|
|
lnk_ip6tnl.remote = *nmtst_inet6_from_string("fd01::18");
|
|
lnk_ip6tnl.parent_ifindex = ifindex_parent;
|
|
lnk_ip6tnl.tclass = 0;
|
|
lnk_ip6tnl.encap_limit = 0;
|
|
lnk_ip6tnl.flow_label = 1338;
|
|
lnk_ip6tnl.proto = IPPROTO_IPV6;
|
|
lnk_ip6tnl.flags = IP6_TNL_F_IGN_ENCAP_LIMIT | IP6_TNL_F_USE_ORIG_TCLASS;
|
|
break;
|
|
}
|
|
|
|
if (!nmtstp_link_ip6tnl_add(NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip("Cannot create ip6tnl tunnel because of missing ip6_tunnel module "
|
|
"(modprobe ip6_tunnel)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding IP6TNL tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IP6GRE:
|
|
{
|
|
NMPlatformLnkIp6Tnl lnk_ip6tnl = {};
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6gre0")) {
|
|
/* Seems that the ip6_tunnel module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0;
|
|
}
|
|
|
|
lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::42");
|
|
lnk_ip6tnl.remote = *nmtst_inet6_from_string("fd01::aaaa");
|
|
lnk_ip6tnl.parent_ifindex = ifindex_parent;
|
|
lnk_ip6tnl.tclass = 21;
|
|
lnk_ip6tnl.flow_label = 1338;
|
|
lnk_ip6tnl.is_gre = TRUE;
|
|
|
|
if (!nmtstp_link_ip6gre_add(NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip("Cannot create ip6gre tunnel because of missing ip6_gre module "
|
|
"(modprobe ip6_gre)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding IP6GRE tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IP6GRETAP:
|
|
{
|
|
NMPlatformLnkIp6Tnl lnk_ip6tnl = {};
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6gre0")) {
|
|
/* Seems that the ip6_tunnel module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0;
|
|
}
|
|
|
|
lnk_ip6tnl.local = *nmtst_inet6_from_string("fe80::abcd");
|
|
lnk_ip6tnl.remote = *nmtst_inet6_from_string("fc01::bbbb");
|
|
lnk_ip6tnl.parent_ifindex = ifindex_parent;
|
|
lnk_ip6tnl.ttl = 10;
|
|
lnk_ip6tnl.tclass = 22;
|
|
lnk_ip6tnl.flow_label = 1339;
|
|
lnk_ip6tnl.is_gre = TRUE;
|
|
lnk_ip6tnl.is_tap = TRUE;
|
|
|
|
if (!nmtstp_link_ip6gre_add(NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip("Cannot create ip6gretap tunnel because of missing ip6_gre module "
|
|
"(modprobe ip6_gre)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding IP6GRETAP tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_MACVLAN:
|
|
{
|
|
NMPlatformLnkMacvlan lnk_macvlan = {};
|
|
const NMPlatformLink *dummy;
|
|
char buf[256];
|
|
int i;
|
|
|
|
lnk_macvlan.mode = MACVLAN_MODE_BRIDGE;
|
|
lnk_macvlan.no_promisc = FALSE;
|
|
lnk_macvlan.tap = FALSE;
|
|
|
|
/* Since in old kernel versions sysfs files for macvtaps are not
|
|
* namespaced, the creation can fail if a macvtap in another namespace
|
|
* has the same index. Try to detect this situation and skip already
|
|
* used indexes.
|
|
* The fix (17af2bce) is included kernel 4.7, dated 24 July, 2016.
|
|
*/
|
|
for (i = ifindex_parent + 1; i < ifindex_parent + 100; i++) {
|
|
snprintf(buf, sizeof(buf), "/sys/class/macvtap/tap%d", i);
|
|
if (!g_file_test(buf, G_FILE_TEST_IS_SYMLINK))
|
|
break;
|
|
|
|
_LOGD("skipping ifindex %d as already used by a macvtap", i);
|
|
|
|
dummy = nmtstp_link_dummy_add(NM_PLATFORM_GET, FALSE, "dummy-tmp");
|
|
g_assert_cmpint(dummy->ifindex, ==, i);
|
|
nmtstp_link_delete(NM_PLATFORM_GET, FALSE, dummy->ifindex, NULL, TRUE);
|
|
}
|
|
|
|
if (!nmtstp_link_macvlan_add(NULL, ext, DEVICE_NAME, ifindex_parent, &lnk_macvlan))
|
|
g_error("Failed adding MACVLAN interface");
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_MACVTAP:
|
|
{
|
|
NMPlatformLnkMacvlan lnk_macvtap = {};
|
|
|
|
lnk_macvtap.mode = MACVLAN_MODE_PRIVATE;
|
|
lnk_macvtap.no_promisc = FALSE;
|
|
lnk_macvtap.tap = TRUE;
|
|
|
|
if (!nmtstp_link_macvlan_add(NULL, ext, DEVICE_NAME, ifindex_parent, &lnk_macvtap))
|
|
g_error("Failed adding MACVTAP interface");
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_SIT:
|
|
{
|
|
NMPlatformLnkSit lnk_sit = {};
|
|
gboolean gracefully_skip = FALSE;
|
|
|
|
lnk_sit.local = nmtst_inet4_from_string("192.168.200.1");
|
|
lnk_sit.remote = nmtst_inet4_from_string("172.25.100.14");
|
|
lnk_sit.parent_ifindex = ifindex_parent;
|
|
lnk_sit.ttl = 0;
|
|
lnk_sit.tos = 31;
|
|
lnk_sit.path_mtu_discovery = FALSE;
|
|
|
|
if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "sit0")) {
|
|
/* Seems that the sit module is not loaded... try to load it. */
|
|
gracefully_skip = nm_utils_modprobe(NULL, TRUE, "sit", NULL) != 0;
|
|
}
|
|
|
|
if (!nmtstp_link_sit_add(NULL, ext, DEVICE_NAME, &lnk_sit)) {
|
|
if (gracefully_skip) {
|
|
g_test_skip(
|
|
"Cannot create sit tunnel because of missing sit module (modprobe sit)");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding SIT tunnel");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_VLAN:
|
|
nmtstp_run_command_check("ip link add name %s link %s type vlan id 1242",
|
|
DEVICE_NAME,
|
|
PARENT_NAME);
|
|
break;
|
|
case NM_LINK_TYPE_VRF:
|
|
{
|
|
NMPlatformLnkVrf lnk_vrf = {};
|
|
gboolean not_supported;
|
|
|
|
lnk_vrf.table = 9876;
|
|
|
|
if (!nmtstp_link_vrf_add(NULL, ext, DEVICE_NAME, &lnk_vrf, ¬_supported)) {
|
|
if (not_supported) {
|
|
g_test_skip("Cannot create VRF interface because of missing kernel support");
|
|
goto out_delete_parent;
|
|
}
|
|
g_error("Failed adding VRF interface");
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_VXLAN:
|
|
{
|
|
NMPlatformLnkVxlan lnk_vxlan = {};
|
|
|
|
switch (test_data->test_mode) {
|
|
case 0:
|
|
lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, PARENT_NAME);
|
|
lnk_vxlan.id = 42;
|
|
lnk_vxlan.local = nmtst_inet4_from_string("23.1.2.164");
|
|
lnk_vxlan.group = nmtst_inet4_from_string("239.1.2.134");
|
|
lnk_vxlan.dst_port = 4789;
|
|
lnk_vxlan.learning = TRUE;
|
|
lnk_vxlan.ageing = 1245;
|
|
break;
|
|
case 1:
|
|
lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, PARENT_NAME);
|
|
lnk_vxlan.id = 11214423;
|
|
lnk_vxlan.local6 = *nmtst_inet6_from_string("1:2:3:4:334:23::23");
|
|
lnk_vxlan.group6 = *nmtst_inet6_from_string("ff0e::115");
|
|
lnk_vxlan.ttl = 32;
|
|
lnk_vxlan.dst_port = 57412;
|
|
lnk_vxlan.src_port_min = 1000;
|
|
lnk_vxlan.src_port_max = 1003;
|
|
lnk_vxlan.learning = TRUE;
|
|
lnk_vxlan.ageing = 3245;
|
|
break;
|
|
}
|
|
|
|
g_assert(nmtstp_link_vxlan_add(NULL, ext, DEVICE_NAME, &lnk_vxlan));
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_TUN:
|
|
{
|
|
gboolean owner_valid = nmtst_get_rand_bool();
|
|
gboolean group_valid = nmtst_get_rand_bool();
|
|
|
|
switch (test_data->test_mode) {
|
|
case 0:
|
|
lnk_tun = (NMPlatformLnkTun){
|
|
.type = nmtst_get_rand_bool() ? IFF_TUN : IFF_TAP,
|
|
.owner = owner_valid ? getuid() : 0,
|
|
.owner_valid = owner_valid,
|
|
.group = group_valid ? getgid() : 0,
|
|
.group_valid = group_valid,
|
|
.pi = nmtst_get_rand_bool(),
|
|
.vnet_hdr = nmtst_get_rand_bool(),
|
|
.multi_queue = nmtst_get_rand_bool(),
|
|
|
|
/* if we add the device via iproute2 (external), we can only
|
|
* create persistent devices. */
|
|
.persist = (ext == 1) ? TRUE : nmtst_get_rand_bool(),
|
|
};
|
|
break;
|
|
default:
|
|
g_assert_not_reached();
|
|
break;
|
|
}
|
|
|
|
g_assert(nmtstp_link_tun_add(NULL,
|
|
ext,
|
|
DEVICE_NAME,
|
|
&lnk_tun,
|
|
(!lnk_tun.persist || nmtst_get_rand_bool()) ? &tun_fd : NULL));
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_WIREGUARD:
|
|
{
|
|
const NMPlatformLink *link;
|
|
|
|
r = nm_platform_link_wireguard_add(NM_PLATFORM_GET, DEVICE_NAME, &link);
|
|
if (r == -EOPNOTSUPP) {
|
|
g_test_skip("wireguard not supported (modprobe wireguard?)");
|
|
goto out_delete_parent;
|
|
}
|
|
|
|
g_assert(NMTST_NM_ERR_SUCCESS(r));
|
|
g_assert(NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(link)) == NMP_OBJECT_TYPE_LINK);
|
|
break;
|
|
}
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
ifindex = nmtstp_assert_wait_for_link(NM_PLATFORM_GET, DEVICE_NAME, test_data->link_type, 100)
|
|
->ifindex;
|
|
|
|
nmtstp_link_set_updown(NULL, -1, ifindex_parent, TRUE);
|
|
|
|
for (i_step = 0; i_step < 5; i_step++) {
|
|
_LOGD("test-software-detect: step %u", i_step);
|
|
if (nmtst_is_debug())
|
|
nmtstp_run_command_check("ip -d link show %s", DEVICE_NAME);
|
|
|
|
if (i_step > 0) {
|
|
gboolean set_up = (i_step % 2) == 1;
|
|
|
|
if (test_data->link_type == NM_LINK_TYPE_VXLAN && set_up) {
|
|
/* On RHEL-7, we need to add a tiny sleep here, otherwise,
|
|
* upping the vxlan device fails with EADDRINUSE.
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1277131 */
|
|
g_usleep(1);
|
|
}
|
|
nmtstp_link_set_updown(NULL, -1, ifindex, set_up);
|
|
}
|
|
|
|
lnk = nm_platform_link_get_lnk(NM_PLATFORM_GET, ifindex, test_data->link_type, &plink);
|
|
g_assert(plink);
|
|
g_assert_cmpint(plink->ifindex, ==, ifindex);
|
|
|
|
if (!lnk && test_data->link_type == NM_LINK_TYPE_TUN) {
|
|
/* this is ok. Kernel apparently does not support tun properties via netlink. We
|
|
* fetch them from sysfs below. */
|
|
} else
|
|
g_assert(lnk);
|
|
|
|
switch (test_data->link_type) {
|
|
case NM_LINK_TYPE_BRIDGE:
|
|
{
|
|
const NMPlatformLnkBridge *plnk = &lnk->lnk_bridge;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_bridge(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(nm_platform_lnk_bridge_cmp(&lnk_bridge, plnk), ==, 0);
|
|
g_assert_cmpint(plnk->forward_delay, ==, 1560);
|
|
g_assert_cmpint(plnk->hello_time, ==, 150);
|
|
g_assert_cmpint(plnk->max_age, ==, 2100);
|
|
g_assert_cmpint(plnk->ageing_time, ==, 2200);
|
|
g_assert_cmpint(plnk->stp_state, ==, TRUE);
|
|
g_assert_cmpint(plnk->priority, ==, 22);
|
|
g_assert_cmpint(plnk->vlan_protocol, ==, 0x8100);
|
|
g_assert_cmpint(plnk->vlan_stats_enabled, ==, lnk_bridge.vlan_stats_enabled);
|
|
g_assert_cmpint(plnk->group_fwd_mask, ==, 8);
|
|
g_assert_cmpint(plnk->mcast_snooping, ==, TRUE);
|
|
g_assert_cmpint(plnk->mcast_router, ==, 1);
|
|
g_assert_cmpint(plnk->mcast_query_use_ifaddr, ==, TRUE);
|
|
g_assert_cmpint(plnk->mcast_querier, ==, TRUE);
|
|
g_assert_cmpint(plnk->mcast_hash_max, ==, 1024);
|
|
g_assert_cmpint(plnk->mcast_last_member_count, ==, 2);
|
|
g_assert_cmpint(plnk->mcast_startup_query_count, ==, 3);
|
|
g_assert_cmpint(plnk->mcast_last_member_interval, ==, 5000);
|
|
g_assert_cmpint(plnk->mcast_membership_interval, ==, 25000);
|
|
g_assert_cmpint(plnk->mcast_querier_interval, ==, 26000);
|
|
g_assert_cmpint(plnk->mcast_query_interval, ==, 12000);
|
|
g_assert_cmpint(plnk->mcast_query_response_interval, ==, 5200);
|
|
g_assert_cmpint(plnk->mcast_startup_query_interval, ==, 3000);
|
|
g_assert_cmpint(nm_platform_lnk_bridge_cmp(&lnk_bridge, plnk), ==, 0);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_GRE:
|
|
{
|
|
const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_gre(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert(nm_platform_lnk_gre_cmp(plnk, &lnk_gre) == 0);
|
|
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_GRETAP:
|
|
{
|
|
const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_gretap(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert(nm_platform_lnk_gre_cmp(plnk, &lnk_gre) == 0);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IP6TNL:
|
|
{
|
|
const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
|
|
|
|
switch (test_data->test_mode) {
|
|
case 0:
|
|
g_assert(plnk == nm_platform_link_get_lnk_ip6tnl(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, ==, ifindex_parent);
|
|
nmtst_assert_ip6_address(&plnk->local, "fd01::15");
|
|
nmtst_assert_ip6_address(&plnk->remote, "fd01::16");
|
|
g_assert_cmpint(plnk->ttl, ==, 0);
|
|
g_assert_cmpint(plnk->tclass, ==, 20);
|
|
g_assert_cmpint(plnk->encap_limit, ==, 6);
|
|
g_assert_cmpint(plnk->flow_label, ==, 1337);
|
|
g_assert_cmpint(plnk->proto, ==, IPPROTO_IPV6);
|
|
break;
|
|
case 1:
|
|
g_assert(plnk == nm_platform_link_get_lnk_ip6tnl(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, ==, ifindex_parent);
|
|
nmtst_assert_ip6_address(&plnk->local, "fd01::17");
|
|
nmtst_assert_ip6_address(&plnk->remote, "fd01::18");
|
|
g_assert_cmpint(plnk->ttl, ==, 0);
|
|
g_assert_cmpint(plnk->flow_label, ==, 1338);
|
|
g_assert_cmpint(plnk->proto, ==, IPPROTO_IPV6);
|
|
g_assert_cmpint(plnk->flags & 0xFFFF, /* ignore kernel internal flags */
|
|
==,
|
|
IP6_TNL_F_IGN_ENCAP_LIMIT | IP6_TNL_F_USE_ORIG_TCLASS);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IP6GRE:
|
|
{
|
|
const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_ip6gre(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, ==, ifindex_parent);
|
|
nmtst_assert_ip6_address(&plnk->local, "fd01::42");
|
|
nmtst_assert_ip6_address(&plnk->remote, "fd01::aaaa");
|
|
g_assert_cmpint(plnk->tclass, ==, 21);
|
|
g_assert_cmpint(plnk->flow_label, ==, 1338);
|
|
g_assert_cmpint(plnk->is_gre, ==, TRUE);
|
|
g_assert_cmpint(plnk->is_tap, ==, FALSE);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IP6GRETAP:
|
|
{
|
|
const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_ip6gretap(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, ==, ifindex_parent);
|
|
nmtst_assert_ip6_address(&plnk->local, "fe80::abcd");
|
|
nmtst_assert_ip6_address(&plnk->remote, "fc01::bbbb");
|
|
g_assert_cmpint(plnk->ttl, ==, 10);
|
|
g_assert_cmpint(plnk->tclass, ==, 22);
|
|
g_assert_cmpint(plnk->flow_label, ==, 1339);
|
|
g_assert_cmpint(plnk->is_gre, ==, TRUE);
|
|
g_assert_cmpint(plnk->is_tap, ==, TRUE);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_IPIP:
|
|
{
|
|
const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_ipip(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, ==, ifindex_parent);
|
|
nmtst_assert_ip4_address(plnk->local, "1.2.3.4");
|
|
nmtst_assert_ip4_address(plnk->remote, "5.6.7.8");
|
|
g_assert_cmpint(plnk->ttl, ==, 0);
|
|
g_assert_cmpint(plnk->tos, ==, 32);
|
|
g_assert_cmpint(plnk->path_mtu_discovery, ==, FALSE);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_MACVLAN:
|
|
{
|
|
const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_macvlan(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->no_promisc, ==, FALSE);
|
|
g_assert_cmpint(plnk->mode, ==, MACVLAN_MODE_BRIDGE);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_MACVTAP:
|
|
{
|
|
const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_macvtap(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->no_promisc, ==, FALSE);
|
|
g_assert_cmpint(plnk->mode, ==, MACVLAN_MODE_PRIVATE);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_SIT:
|
|
{
|
|
const NMPlatformLnkSit *plnk = &lnk->lnk_sit;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_sit(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, ==, ifindex_parent);
|
|
nmtst_assert_ip4_address(plnk->local, "192.168.200.1");
|
|
nmtst_assert_ip4_address(plnk->remote, "172.25.100.14");
|
|
g_assert_cmpint(plnk->ttl, ==, 0);
|
|
g_assert_cmpint(plnk->tos, ==, 31);
|
|
g_assert_cmpint(plnk->path_mtu_discovery, ==, FALSE);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_TUN:
|
|
{
|
|
const NMPlatformLnkTun *plnk;
|
|
NMPlatformLnkTun lnk_tun2;
|
|
|
|
g_assert((lnk ? &lnk->lnk_tun : NULL)
|
|
== nm_platform_link_get_lnk_tun(NM_PLATFORM_GET, ifindex, NULL));
|
|
|
|
/* kernel might not expose tun options via netlink. Either way, try
|
|
* to read them (either from platform cache, or fallback to sysfs).
|
|
* See also: rh#1547213. */
|
|
if (!nm_platform_link_tun_get_properties(NM_PLATFORM_GET, ifindex, &lnk_tun2))
|
|
g_assert_not_reached();
|
|
|
|
plnk = lnk ? &lnk->lnk_tun : &lnk_tun2;
|
|
if (lnk)
|
|
g_assert(memcmp(plnk, &lnk_tun2, sizeof(NMPlatformLnkTun)) == 0);
|
|
|
|
if (i_step == 0) {
|
|
/* Before we upped the device for the first time the kernel didn't notify
|
|
* us of the owner set after the link creation:
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1566062
|
|
*/
|
|
break;
|
|
}
|
|
|
|
g_assert(nm_platform_lnk_tun_cmp(plnk, &lnk_tun) == 0);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_VLAN:
|
|
{
|
|
const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->id, ==, 1242);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_VRF:
|
|
{
|
|
const NMPlatformLnkVrf *plnk = &lnk->lnk_vrf;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_vrf(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->table, ==, 9876);
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_VXLAN:
|
|
{
|
|
const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_vxlan(NM_PLATFORM_GET, ifindex, NULL));
|
|
g_assert_cmpint(plnk->parent_ifindex, !=, 0);
|
|
g_assert_cmpint(plnk->tos, ==, 0);
|
|
g_assert_cmpint(plnk->learning, ==, TRUE);
|
|
g_assert_cmpint(plnk->limit, ==, 0);
|
|
g_assert_cmpint(plnk->proxy, ==, FALSE);
|
|
g_assert_cmpint(plnk->rsc, ==, FALSE);
|
|
g_assert_cmpint(plnk->l2miss, ==, FALSE);
|
|
g_assert_cmpint(plnk->l3miss, ==, FALSE);
|
|
|
|
switch (test_data->test_mode) {
|
|
case 0:
|
|
g_assert_cmpint(plnk->id, ==, 42);
|
|
nmtst_assert_ip4_address(plnk->local, "23.1.2.164");
|
|
nmtst_assert_ip4_address(plnk->group, "239.1.2.134");
|
|
nmtst_assert_ip6_address(&plnk->group6, "::");
|
|
nmtst_assert_ip6_address(&plnk->local6, "::");
|
|
g_assert_cmpint(plnk->ttl, ==, 0);
|
|
g_assert_cmpint(plnk->ageing, ==, 1245);
|
|
g_assert_cmpint(plnk->dst_port, ==, 4789);
|
|
if (plnk->src_port_min != 0 || plnk->src_port_max != 0) {
|
|
/* on some kernels, omitting the port range results in setting
|
|
* following default port range. */
|
|
g_assert_cmpint(plnk->src_port_min, ==, 32768);
|
|
g_assert_cmpint(plnk->src_port_max, ==, 61000);
|
|
}
|
|
break;
|
|
case 1:
|
|
g_assert_cmpint(plnk->id, ==, 11214423);
|
|
nmtst_assert_ip4_address(plnk->local, "0.0.0.0");
|
|
nmtst_assert_ip4_address(plnk->group, "0.0.0.0");
|
|
nmtst_assert_ip6_address(&plnk->group6, "ff0e::115");
|
|
nmtst_assert_ip6_address(&plnk->local6, "1:2:3:4:334:23::23");
|
|
g_assert_cmpint(plnk->ageing, ==, 3245);
|
|
g_assert_cmpint(plnk->dst_port, ==, 57412);
|
|
g_assert_cmpint(plnk->ttl, ==, 32);
|
|
g_assert_cmpint(plnk->src_port_min, ==, 1000);
|
|
g_assert_cmpint(plnk->src_port_max, ==, 1003);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case NM_LINK_TYPE_WIREGUARD:
|
|
{
|
|
const NMPlatformLnkWireGuard *plnk = &lnk->lnk_wireguard;
|
|
|
|
g_assert(plnk == nm_platform_link_get_lnk_wireguard(NM_PLATFORM_GET, ifindex, NULL));
|
|
|
|
if (plink->n_ifi_flags & IFF_UP) {
|
|
_test_wireguard_change(NM_PLATFORM_GET, plink->ifindex, test_data->test_mode);
|
|
if (_LOGD_ENABLED())
|
|
_system("WG_HIDE_KEYS=never wg show all");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
|
|
nmtstp_link_delete(NULL, -1, ifindex, DEVICE_NAME, TRUE);
|
|
out_delete_parent:
|
|
nmtstp_link_delete(NULL, -1, ifindex_parent, PARENT_NAME, TRUE);
|
|
}
|
|
|
|
static void
|
|
test_software_detect_add(const char *testpath, NMLinkType link_type, int test_mode)
|
|
{
|
|
TestAddSoftwareDetectData *test_data;
|
|
char * path;
|
|
|
|
test_data = g_new0(TestAddSoftwareDetectData, 1);
|
|
test_data->link_type = link_type;
|
|
test_data->test_mode = test_mode;
|
|
test_data->external_command = TRUE;
|
|
|
|
path = g_strdup_printf("%s/external", testpath);
|
|
g_test_add_data_func_full(path, test_data, test_software_detect, g_free);
|
|
g_free(path);
|
|
|
|
test_data = g_new0(TestAddSoftwareDetectData, 1);
|
|
test_data->link_type = link_type;
|
|
test_data->test_mode = test_mode;
|
|
test_data->external_command = FALSE;
|
|
|
|
path = g_strdup_printf("%s/platform", testpath);
|
|
g_test_add_data_func_full(path, test_data, test_software_detect, g_free);
|
|
g_free(path);
|
|
|
|
test_data = g_new0(TestAddSoftwareDetectData, 1);
|
|
test_data->link_type = link_type;
|
|
test_data->test_mode = test_mode;
|
|
test_data->external_command = -1;
|
|
|
|
path = g_strdup_printf("%s/random", testpath);
|
|
g_test_add_data_func_full(path, test_data, test_software_detect, g_free);
|
|
g_free(path);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_assert_xgress_qos_mappings_impl(int ifindex, gboolean is_ingress_map, int n_entries, int n, ...)
|
|
{
|
|
const NMPlatformLink * plink;
|
|
const NMPObject * lnk;
|
|
guint n_map;
|
|
const NMVlanQosMapping *map;
|
|
va_list ap;
|
|
guint i;
|
|
|
|
lnk = nm_platform_link_get_lnk(NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink);
|
|
|
|
g_assert(plink);
|
|
g_assert_cmpint(plink->ifindex, ==, ifindex);
|
|
g_assert(lnk);
|
|
g_assert(&lnk->lnk_vlan == nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, ifindex, NULL));
|
|
|
|
if (nmtst_is_debug())
|
|
nmtstp_run_command_check("ip -d link show %s", plink->name);
|
|
|
|
if (is_ingress_map) {
|
|
map = lnk->_lnk_vlan.ingress_qos_map;
|
|
n_map = lnk->_lnk_vlan.n_ingress_qos_map;
|
|
} else {
|
|
map = lnk->_lnk_vlan.egress_qos_map;
|
|
n_map = lnk->_lnk_vlan.n_egress_qos_map;
|
|
}
|
|
|
|
if (n_entries != -1)
|
|
g_assert_cmpint(n_map, ==, n_entries);
|
|
|
|
for (i = 0; i < n_map; i++) {
|
|
if (is_ingress_map) {
|
|
g_assert_cmpint(map[i].from, >=, 0);
|
|
g_assert_cmpint(map[i].from, <=, 7);
|
|
}
|
|
if (i > 0)
|
|
g_assert_cmpint(map[i - 1].from, <, map[i].from);
|
|
}
|
|
|
|
va_start(ap, n);
|
|
for (; n > 0; n--) {
|
|
gboolean found = FALSE;
|
|
guint from = va_arg(ap, guint);
|
|
guint to = va_arg(ap, guint);
|
|
|
|
for (i = 0; i < n_map; i++) {
|
|
if (map[i].from == from) {
|
|
g_assert(!found);
|
|
found = TRUE;
|
|
|
|
g_assert(map[i].to == to);
|
|
}
|
|
}
|
|
g_assert(found);
|
|
}
|
|
va_end(ap);
|
|
}
|
|
#define _assert_xgress_qos_mappings(ifindex, is_ingress_map, n_entries, ...) \
|
|
_assert_xgress_qos_mappings_impl( \
|
|
(ifindex), \
|
|
(is_ingress_map), \
|
|
(n_entries), \
|
|
(G_STATIC_ASSERT_EXPR((NM_NARG(__VA_ARGS__) % 2) == 0), NM_NARG(__VA_ARGS__) / 2), \
|
|
__VA_ARGS__)
|
|
#define _assert_ingress_qos_mappings(ifindex, n_entries, ...) \
|
|
_assert_xgress_qos_mappings(ifindex, TRUE, n_entries, __VA_ARGS__)
|
|
#define _assert_egress_qos_mappings(ifindex, n_entries, ...) \
|
|
_assert_xgress_qos_mappings(ifindex, FALSE, n_entries, __VA_ARGS__)
|
|
|
|
static void
|
|
_assert_vlan_flags(int ifindex, NMVlanFlags flags)
|
|
{
|
|
const NMPlatformLnkVlan *plnk;
|
|
|
|
plnk = nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, ifindex, NULL);
|
|
g_assert(plnk);
|
|
g_assert_cmpint(plnk->flags, ==, flags);
|
|
}
|
|
|
|
static void
|
|
test_vlan_set_xgress(void)
|
|
{
|
|
int ifindex, ifindex_parent;
|
|
|
|
nmtstp_run_command_check("ip link add %s type dummy", PARENT_NAME);
|
|
ifindex_parent =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
|
|
|
|
nmtstp_run_command_check("ip link add name %s link %s type vlan id 1245",
|
|
DEVICE_NAME,
|
|
PARENT_NAME);
|
|
ifindex =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex;
|
|
|
|
/* ingress-qos-map */
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 4, 5));
|
|
_assert_ingress_qos_mappings(ifindex, 1, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 3, 7));
|
|
_assert_ingress_qos_mappings(ifindex, 2, 3, 7, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 3, 8));
|
|
_assert_ingress_qos_mappings(ifindex, 2, 3, 8, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 0, 4));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, 4, 3, 8, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, G_MAXUINT32, 3, 8, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32 - 1));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, G_MAXUINT32 - 1, 3, 8, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 0, 5));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, 5, 3, 8, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 0, 5));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, 5, 3, 8, 4, 5);
|
|
|
|
/* Set invalid values: */
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 8, 3));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, 5, 3, 8, 4, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_ingress_map(NM_PLATFORM_GET, ifindex, 9, 4));
|
|
_assert_ingress_qos_mappings(ifindex, 3, 0, 5, 3, 8, 4, 5);
|
|
|
|
/* egress-qos-map */
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 7, 3));
|
|
_assert_egress_qos_mappings(ifindex, 1, 7, 3);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 8, 4));
|
|
_assert_egress_qos_mappings(ifindex, 2, 7, 3, 8, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 0, 4));
|
|
_assert_egress_qos_mappings(ifindex, 3, 0, 4, 7, 3, 8, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 1, 4));
|
|
_assert_egress_qos_mappings(ifindex, 4, 0, 4, 1, 4, 7, 3, 8, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 1, 5));
|
|
_assert_egress_qos_mappings(ifindex, 4, 0, 4, 1, 5, 7, 3, 8, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 9, 5));
|
|
_assert_egress_qos_mappings(ifindex, 5, 0, 4, 1, 5, 7, 3, 8, 4, 9, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 8, 5));
|
|
_assert_egress_qos_mappings(ifindex, 5, 0, 4, 1, 5, 7, 3, 8, 5, 9, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 8, 0));
|
|
_assert_egress_qos_mappings(ifindex, 4, 0, 4, 1, 5, 7, 3, 9, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 0, 0));
|
|
_assert_egress_qos_mappings(ifindex, 3, 1, 5, 7, 3, 9, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 100, 4));
|
|
_assert_egress_qos_mappings(ifindex, 4, 1, 5, 7, 3, 9, 5, 100, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, G_MAXUINT32, 4));
|
|
_assert_egress_qos_mappings(ifindex, 5, 1, 5, 7, 3, 9, 5, 100, 4, G_MAXUINT32, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, G_MAXUINT32, 8));
|
|
_assert_egress_qos_mappings(ifindex, 5, 1, 5, 7, 3, 9, 5, 100, 4, G_MAXUINT32, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, G_MAXUINT32, 0));
|
|
_assert_egress_qos_mappings(ifindex, 4, 1, 5, 7, 3, 9, 5, 100, 4);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 100, 0));
|
|
_assert_egress_qos_mappings(ifindex, 3, 1, 5, 7, 3, 9, 5);
|
|
|
|
g_assert(nm_platform_link_vlan_set_egress_map(NM_PLATFORM_GET, ifindex, 1, 0));
|
|
_assert_egress_qos_mappings(ifindex, 2, 7, 3, 9, 5);
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 1, .to = 5},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
TRUE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
FALSE,
|
|
NULL,
|
|
0));
|
|
_assert_ingress_qos_mappings(ifindex, 1, 1, 5);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 3, .to = 5},
|
|
{.from = 7, .to = 1655},
|
|
{.from = 7, .to = 17655},
|
|
{.from = 5, .to = 754},
|
|
{.from = 4, .to = 12},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
TRUE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
FALSE,
|
|
NULL,
|
|
0));
|
|
_assert_ingress_qos_mappings(ifindex, 4, 3, 5, 4, 12, 7, 17655, 5, 754);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 3, .to = 18},
|
|
{.from = 6, .to = 121},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
FALSE,
|
|
NULL,
|
|
0));
|
|
_assert_ingress_qos_mappings(ifindex, 5, 3, 18, 4, 12, 6, 121, 7, 17655, 5, 754);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 3, .to = 0},
|
|
{.from = 6, .to = 7},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
TRUE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
FALSE,
|
|
NULL,
|
|
0));
|
|
_assert_ingress_qos_mappings(ifindex, 1, 6, 7);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 1, .to = 5},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
TRUE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
FALSE,
|
|
NULL,
|
|
0));
|
|
_assert_ingress_qos_mappings(ifindex, 1, 1, 5);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 5, .to = 1},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_egress_qos_mappings(ifindex, 1, 5, 1);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 5, .to = 3},
|
|
{.from = 1655, .to = 5},
|
|
{.from = 1655, .to = 7},
|
|
{.from = G_MAXUINT32, .to = 6},
|
|
{.from = G_MAXUINT32, .to = 8},
|
|
{.from = 754, .to = 4},
|
|
{.from = 3, .to = 2},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_egress_qos_mappings(ifindex, 5, 3, 2, 5, 3, 754, 4, 1655, 7, G_MAXUINT32, 6);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 754, .to = 3},
|
|
{.from = 755, .to = 8},
|
|
{.from = 1655, .to = 0},
|
|
{.from = 6, .to = 1},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
FALSE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_egress_qos_mappings(ifindex, 5, 3, 2, 5, 3, 6, 1, 754, 3, G_MAXUINT32, 6);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 6, .to = 0},
|
|
{.from = 3, .to = 4},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_egress_qos_mappings(ifindex, 1, 3, 4);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 1, .to = 5},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_egress_qos_mappings(ifindex, 1, 1, 5);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 6, .to = 145},
|
|
{.from = 4, .to = 1},
|
|
{.from = 6, .to = 12},
|
|
};
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 1, .to = 5},
|
|
{.from = 3232, .to = 7},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP,
|
|
NM_VLAN_FLAG_REORDER_HEADERS,
|
|
TRUE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
TRUE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_ingress_qos_mappings(ifindex, 2, 4, 1, 6, 12);
|
|
_assert_egress_qos_mappings(ifindex, 2, 1, 5, 3232, 7);
|
|
_assert_vlan_flags(ifindex, NM_VLAN_FLAG_REORDER_HEADERS);
|
|
}
|
|
|
|
{
|
|
const NMVlanQosMapping ingress_map[] = {
|
|
{.from = 6, .to = 145},
|
|
{.from = 4, .to = 1},
|
|
{.from = 6, .to = 12},
|
|
};
|
|
const NMVlanQosMapping egress_map[] = {
|
|
{.from = 1, .to = 7},
|
|
{.from = 64, .to = 10},
|
|
{.from = 64, .to = 10},
|
|
{.from = 64, .to = 10},
|
|
{.from = 64, .to = 10},
|
|
{.from = 3232, .to = 0},
|
|
{.from = 64, .to = 4},
|
|
};
|
|
|
|
g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET,
|
|
ifindex,
|
|
NM_VLAN_FLAG_GVRP,
|
|
NM_VLAN_FLAG_GVRP,
|
|
FALSE,
|
|
ingress_map,
|
|
G_N_ELEMENTS(ingress_map),
|
|
FALSE,
|
|
egress_map,
|
|
G_N_ELEMENTS(egress_map)));
|
|
_assert_ingress_qos_mappings(ifindex, 2, 4, 1, 6, 12);
|
|
_assert_egress_qos_mappings(ifindex, 2, 1, 7, 64, 4);
|
|
_assert_vlan_flags(ifindex, NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP);
|
|
}
|
|
|
|
nmtstp_link_delete(NULL, -1, ifindex, DEVICE_NAME, TRUE);
|
|
nmtstp_link_delete(NULL, -1, ifindex_parent, PARENT_NAME, TRUE);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_create_many_links_do(guint n_devices)
|
|
{
|
|
gint64 time, start_time = nm_utils_get_monotonic_timestamp_nsec();
|
|
guint i;
|
|
char name[64];
|
|
const NMPlatformLink *pllink;
|
|
gs_unref_array GArray *ifindexes = g_array_sized_new(FALSE, FALSE, sizeof(int), n_devices);
|
|
const int EX = ((int) (nmtst_get_rand_uint32() % 4)) - 1;
|
|
|
|
g_assert(EX >= -1 && EX <= 2);
|
|
|
|
_LOGI(">>> create devices (EX=%d)...", EX);
|
|
|
|
for (i = 0; i < n_devices; i++) {
|
|
nm_sprintf_buf(name, "t-%05u", i);
|
|
if (EX == 2) {
|
|
/* This mode is different from letting nmtstp_link_dummy_add()
|
|
* because in this case we don't process any platform events
|
|
* while adding all the links. */
|
|
nmtstp_run_command_check("ip link add %s type dummy", name);
|
|
} else
|
|
nmtstp_link_dummy_add(NULL, EX, name);
|
|
}
|
|
|
|
_LOGI(">>> process events after creating devices...");
|
|
|
|
nm_platform_process_events(NM_PLATFORM_GET);
|
|
|
|
_LOGI(">>> check devices...");
|
|
|
|
for (i = 0; i < n_devices; i++) {
|
|
nm_sprintf_buf(name, "t-%05u", i);
|
|
|
|
pllink = nm_platform_link_get_by_ifname(NM_PLATFORM_GET, name);
|
|
g_assert(pllink);
|
|
g_assert_cmpint(pllink->type, ==, NM_LINK_TYPE_DUMMY);
|
|
g_assert_cmpstr(pllink->name, ==, name);
|
|
|
|
g_array_append_val(ifindexes, pllink->ifindex);
|
|
}
|
|
|
|
_LOGI(">>> delete devices...");
|
|
|
|
g_assert_cmpint(ifindexes->len, ==, n_devices);
|
|
for (i = 0; i < n_devices; i++) {
|
|
nm_sprintf_buf(name, "t-%05u", i);
|
|
|
|
if (EX == 2)
|
|
nmtstp_run_command_check("ip link delete %s", name);
|
|
else
|
|
nmtstp_link_delete(NULL, EX, g_array_index(ifindexes, int, i), name, TRUE);
|
|
}
|
|
|
|
_LOGI(">>> process events after deleting devices...");
|
|
nm_platform_process_events(NM_PLATFORM_GET);
|
|
|
|
time = nm_utils_get_monotonic_timestamp_nsec() - start_time;
|
|
_LOGI(">>> finished in %ld.%09ld seconds",
|
|
(long) (time / NM_UTILS_NSEC_PER_SEC),
|
|
(long) (time % NM_UTILS_NSEC_PER_SEC));
|
|
}
|
|
|
|
static void
|
|
test_create_many_links(gconstpointer user_data)
|
|
{
|
|
guint n_devices = GPOINTER_TO_UINT(user_data);
|
|
|
|
if (n_devices > 100 && nmtst_test_quick()) {
|
|
g_print("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n",
|
|
g_get_prgname() ?: "test-link-linux");
|
|
g_test_skip("Skip long running test");
|
|
return;
|
|
}
|
|
|
|
test_create_many_links_do(n_devices);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nl_bugs_veth(void)
|
|
{
|
|
const char * IFACE_VETH0 = "nm-test-veth0";
|
|
const char * IFACE_VETH1 = "nm-test-veth1";
|
|
int ifindex_veth0, ifindex_veth1;
|
|
int i;
|
|
const NMPlatformLink *pllink_veth0, *pllink_veth1;
|
|
gs_free_error GError * error = NULL;
|
|
NMTstpNamespaceHandle *ns_handle = NULL;
|
|
|
|
/* create veth pair. */
|
|
ifindex_veth0 = nmtstp_link_veth_add(NM_PLATFORM_GET, -1, IFACE_VETH0, IFACE_VETH1)->ifindex;
|
|
ifindex_veth1 =
|
|
nmtstp_link_get_typed(NM_PLATFORM_GET, -1, IFACE_VETH1, NM_LINK_TYPE_VETH)->ifindex;
|
|
|
|
/* assert that nm_platform_link_veth_get_properties() returns the expected peer ifindexes. */
|
|
g_assert(nm_platform_link_veth_get_properties(NM_PLATFORM_GET, ifindex_veth0, &i));
|
|
g_assert_cmpint(i, ==, ifindex_veth1);
|
|
|
|
g_assert(nm_platform_link_veth_get_properties(NM_PLATFORM_GET, ifindex_veth1, &i));
|
|
g_assert_cmpint(i, ==, ifindex_veth0);
|
|
|
|
/* assert that NMPlatformLink.parent is the peer-ifindex. */
|
|
pllink_veth0 = nm_platform_link_get(NM_PLATFORM_GET, ifindex_veth0);
|
|
g_assert(pllink_veth0);
|
|
if (pllink_veth0->parent == 0) {
|
|
/* Kernels prior to 4.1 dated 21 June, 2015 don't support exposing the veth peer
|
|
* as IFA_LINK. skip the remainder of the test. */
|
|
goto out;
|
|
}
|
|
g_assert_cmpint(pllink_veth0->parent, ==, ifindex_veth1);
|
|
|
|
/* The following tests whether we have a workaround for kernel bug
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1285827 in place. */
|
|
pllink_veth1 = nm_platform_link_get(NM_PLATFORM_GET, ifindex_veth1);
|
|
g_assert(pllink_veth1);
|
|
g_assert_cmpint(pllink_veth1->parent, ==, ifindex_veth0);
|
|
|
|
/* move one veth peer to another namespace and check that the
|
|
* parent/IFLA_LINK of the remaining peer properly updates
|
|
* (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */
|
|
ns_handle = nmtstp_namespace_create(CLONE_NEWNET, &error);
|
|
g_assert_no_error(error);
|
|
g_assert(ns_handle);
|
|
|
|
nmtstp_run_command_check("ip link set %s netns %ld",
|
|
IFACE_VETH1,
|
|
(long) nmtstp_namespace_handle_get_pid(ns_handle));
|
|
NMTST_WAIT_ASSERT(100, {
|
|
nmtstp_wait_for_signal(NM_PLATFORM_GET, 50);
|
|
nm_platform_process_events(NM_PLATFORM_GET);
|
|
|
|
pllink_veth1 = nm_platform_link_get(NM_PLATFORM_GET, ifindex_veth1);
|
|
pllink_veth0 = nm_platform_link_get(NM_PLATFORM_GET, ifindex_veth0);
|
|
if (!pllink_veth1 && pllink_veth0 && pllink_veth0->parent == NM_PLATFORM_LINK_OTHER_NETNS) {
|
|
break;
|
|
}
|
|
});
|
|
|
|
out:
|
|
nmtstp_link_delete(NULL, -1, ifindex_veth0, IFACE_VETH0, TRUE);
|
|
g_assert(!nmtstp_link_get(NM_PLATFORM_GET, ifindex_veth0, IFACE_VETH0));
|
|
g_assert(!nmtstp_link_get(NM_PLATFORM_GET, ifindex_veth1, IFACE_VETH1));
|
|
nmtstp_namespace_handle_release(ns_handle);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nl_bugs_spuroius_newlink(void)
|
|
{
|
|
const char * IFACE_BOND0 = "nm-test-bond0";
|
|
const char * IFACE_DUMMY0 = "nm-test-dummy0";
|
|
int ifindex_bond0, ifindex_dummy0;
|
|
const NMPlatformLink *pllink;
|
|
gboolean wait_for_settle;
|
|
|
|
/* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */
|
|
|
|
nmtstp_run_command_check("ip link add %s type dummy", IFACE_DUMMY0);
|
|
ifindex_dummy0 =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)
|
|
->ifindex;
|
|
|
|
nmtstp_run_command_check("ip link add %s type bond", IFACE_BOND0);
|
|
ifindex_bond0 =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, IFACE_BOND0, NM_LINK_TYPE_BOND, 100)->ifindex;
|
|
|
|
nmtstp_link_set_updown(NULL, -1, ifindex_bond0, TRUE);
|
|
|
|
nmtstp_run_command_check("ip link set %s master %s", IFACE_DUMMY0, IFACE_BOND0);
|
|
NMTST_WAIT_ASSERT(100, {
|
|
nmtstp_wait_for_signal(NM_PLATFORM_GET, 50);
|
|
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, ifindex_dummy0);
|
|
g_assert(pllink);
|
|
if (pllink->master == ifindex_bond0)
|
|
break;
|
|
});
|
|
|
|
nmtstp_run_command_check("ip link del %s", IFACE_BOND0);
|
|
|
|
wait_for_settle = TRUE;
|
|
nmtstp_wait_for_signal(NM_PLATFORM_GET, 50);
|
|
again:
|
|
nm_platform_process_events(NM_PLATFORM_GET);
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, ifindex_bond0);
|
|
g_assert(!pllink);
|
|
|
|
if (wait_for_settle) {
|
|
wait_for_settle = FALSE;
|
|
NMTST_WAIT(300, { nmtstp_wait_for_signal(NM_PLATFORM_GET, 50); });
|
|
goto again;
|
|
}
|
|
|
|
g_assert(!nmtstp_link_get(NM_PLATFORM_GET, ifindex_bond0, IFACE_BOND0));
|
|
nmtstp_link_delete(NULL, -1, ifindex_dummy0, IFACE_DUMMY0, TRUE);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_nl_bugs_spuroius_dellink(void)
|
|
{
|
|
const char * IFACE_BRIDGE0 = "nm-test-bridge0";
|
|
const char * IFACE_DUMMY0 = "nm-test-dummy0";
|
|
int ifindex_bridge0, ifindex_dummy0;
|
|
const NMPlatformLink *pllink;
|
|
gboolean wait_for_settle;
|
|
|
|
/* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */
|
|
|
|
nmtstp_run_command_check("ip link add %s type dummy", IFACE_DUMMY0);
|
|
ifindex_dummy0 =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)
|
|
->ifindex;
|
|
|
|
nmtstp_run_command_check("ip link add %s type bridge", IFACE_BRIDGE0);
|
|
ifindex_bridge0 =
|
|
nmtstp_assert_wait_for_link(NM_PLATFORM_GET, IFACE_BRIDGE0, NM_LINK_TYPE_BRIDGE, 100)
|
|
->ifindex;
|
|
|
|
nmtstp_link_set_updown(NULL, -1, ifindex_bridge0, TRUE);
|
|
|
|
nmtstp_run_command_check("ip link set %s master %s", IFACE_DUMMY0, IFACE_BRIDGE0);
|
|
NMTST_WAIT_ASSERT(100, {
|
|
nmtstp_wait_for_signal(NM_PLATFORM_GET, 50);
|
|
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, ifindex_dummy0);
|
|
g_assert(pllink);
|
|
if (pllink->master == ifindex_bridge0)
|
|
break;
|
|
});
|
|
|
|
nm_platform_process_events(NM_PLATFORM_GET);
|
|
|
|
nmtstp_run_command_check("ip link set %s nomaster", IFACE_DUMMY0);
|
|
|
|
wait_for_settle = TRUE;
|
|
nmtstp_wait_for_signal(NM_PLATFORM_GET, 50);
|
|
again:
|
|
nm_platform_process_events(NM_PLATFORM_GET);
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, ifindex_bridge0);
|
|
g_assert(pllink);
|
|
pllink = nm_platform_link_get(NM_PLATFORM_GET, ifindex_dummy0);
|
|
g_assert(pllink);
|
|
g_assert_cmpint(pllink->parent, ==, 0);
|
|
|
|
if (wait_for_settle) {
|
|
wait_for_settle = FALSE;
|
|
NMTST_WAIT(300, { nmtstp_wait_for_signal(NM_PLATFORM_GET, 50); });
|
|
goto again;
|
|
}
|
|
|
|
nmtstp_link_delete(NULL, -1, ifindex_bridge0, IFACE_BRIDGE0, TRUE);
|
|
nmtstp_link_delete(NULL, -1, ifindex_dummy0, IFACE_DUMMY0, TRUE);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
_test_netns_setup(gpointer fixture, gconstpointer test_data)
|
|
{
|
|
/* the singleton platform instance has netns support disabled.
|
|
* Destroy the instance before the test and re-create it afterwards. */
|
|
g_object_unref(NM_PLATFORM_GET);
|
|
}
|
|
|
|
static void
|
|
_test_netns_teardown(gpointer fixture, gconstpointer test_data)
|
|
{
|
|
nmtstp_setup_platform();
|
|
}
|
|
|
|
static NMPlatform *
|
|
_test_netns_create_platform(void)
|
|
{
|
|
NMPNetns * netns;
|
|
NMPlatform *platform;
|
|
|
|
netns = nmp_netns_new();
|
|
g_assert(NMP_IS_NETNS(netns));
|
|
|
|
platform = nm_linux_platform_new(TRUE, TRUE);
|
|
g_assert(NM_IS_LINUX_PLATFORM(platform));
|
|
|
|
nmp_netns_pop(netns);
|
|
g_object_unref(netns);
|
|
|
|
return platform;
|
|
}
|
|
|
|
static gboolean
|
|
_test_netns_check_skip(void)
|
|
{
|
|
static int support = -1;
|
|
static int support_errsv = 0;
|
|
NMPNetns * netns;
|
|
gs_unref_object NMPNetns *netns2 = NULL;
|
|
|
|
netns = nmp_netns_get_current();
|
|
if (!netns) {
|
|
g_test_skip("No netns support");
|
|
return TRUE;
|
|
}
|
|
|
|
g_assert(nmp_netns_get_fd_net(netns) > 0);
|
|
|
|
if (support == -1) {
|
|
support = (setns(nmp_netns_get_fd_net(netns), CLONE_NEWNET) == 0);
|
|
if (!support)
|
|
support_errsv = errno;
|
|
}
|
|
if (!support) {
|
|
_LOGD("setns() failed with \"%s\". This indicates missing support (valgrind?)",
|
|
nm_strerror_native(support_errsv));
|
|
g_test_skip("No netns support (setns failed)");
|
|
return TRUE;
|
|
}
|
|
|
|
netns2 = nmp_netns_new();
|
|
if (!netns2) {
|
|
/* skip tests for https://bugzilla.gnome.org/show_bug.cgi?id=790214 */
|
|
g_assert_cmpint(errno, ==, EINVAL);
|
|
g_test_skip("No netns support to create another netns");
|
|
return TRUE;
|
|
}
|
|
nmp_netns_pop(netns2);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
_check_sysctl_skip(void)
|
|
{
|
|
if (access("/proc/sys/net/ipv4/ip_forward", W_OK) == -1) {
|
|
g_test_skip("Can not write sysctls");
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define _sysctl_assert_eq(plat, path, value) \
|
|
G_STMT_START \
|
|
{ \
|
|
gs_free char *_val = NULL; \
|
|
\
|
|
_val = nm_platform_sysctl_get(plat, NMP_SYSCTL_PATHID_ABSOLUTE(path)); \
|
|
g_assert_cmpstr(_val, ==, value); \
|
|
} \
|
|
G_STMT_END
|
|
|
|
static void
|
|
test_netns_general(gpointer fixture, gconstpointer test_data)
|
|
{
|
|
gs_unref_object NMPlatform *platform_1 = NULL;
|
|
gs_unref_object NMPlatform *platform_2 = NULL;
|
|
NMPNetns * netns_tmp;
|
|
char sbuf[100];
|
|
int i, j, k;
|
|
gboolean ethtool_support;
|
|
NMPUtilsEthtoolDriverInfo driver_info;
|
|
|
|
if (_test_netns_check_skip())
|
|
return;
|
|
|
|
if (_check_sysctl_skip())
|
|
return;
|
|
|
|
platform_1 = nm_linux_platform_new(TRUE, TRUE);
|
|
platform_2 = _test_netns_create_platform();
|
|
|
|
/* add some dummy devices. The "other-*" devices are there to bump the ifindex */
|
|
for (k = 0; k < 2; k++) {
|
|
NMPlatform *p = (k == 0 ? platform_1 : platform_2);
|
|
const char *id = (k == 0 ? "a" : "b");
|
|
|
|
for (i = 0, j = nmtst_get_rand_uint32() % 5; i < j; i++)
|
|
_ADD_DUMMY(p, nm_sprintf_buf(sbuf, "other-a-%s-%02d", id, i));
|
|
|
|
_ADD_DUMMY(p, "dummy1_");
|
|
|
|
for (i = 0, j = nmtst_get_rand_uint32() % 5; i < j; i++)
|
|
_ADD_DUMMY(p, nm_sprintf_buf(sbuf, "other-b-%s-%02d", id, i));
|
|
|
|
_ADD_DUMMY(p, nm_sprintf_buf(sbuf, "dummy2%s", id));
|
|
|
|
for (i = 0, j = nmtst_get_rand_uint32() % 5; i < j; i++)
|
|
_ADD_DUMMY(p, nm_sprintf_buf(sbuf, "other-c-%s-%02d", id, i));
|
|
}
|
|
|
|
_sysctl_assert_eq(
|
|
platform_1,
|
|
"/sys/devices/virtual/net/dummy1_/ifindex",
|
|
nm_sprintf_buf(
|
|
sbuf,
|
|
"%d",
|
|
nmtstp_link_get_typed(platform_1, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex));
|
|
_sysctl_assert_eq(
|
|
platform_1,
|
|
"/sys/devices/virtual/net/dummy2a/ifindex",
|
|
nm_sprintf_buf(
|
|
sbuf,
|
|
"%d",
|
|
nmtstp_link_get_typed(platform_1, 0, "dummy2a", NM_LINK_TYPE_DUMMY)->ifindex));
|
|
_sysctl_assert_eq(platform_1, "/sys/devices/virtual/net/dummy2b/ifindex", NULL);
|
|
|
|
_sysctl_assert_eq(
|
|
platform_2,
|
|
"/sys/devices/virtual/net/dummy1_/ifindex",
|
|
nm_sprintf_buf(
|
|
sbuf,
|
|
"%d",
|
|
nmtstp_link_get_typed(platform_2, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex));
|
|
_sysctl_assert_eq(platform_2, "/sys/devices/virtual/net/dummy2a/ifindex", NULL);
|
|
_sysctl_assert_eq(
|
|
platform_2,
|
|
"/sys/devices/virtual/net/dummy2b/ifindex",
|
|
nm_sprintf_buf(
|
|
sbuf,
|
|
"%d",
|
|
nmtstp_link_get_typed(platform_2, 0, "dummy2b", NM_LINK_TYPE_DUMMY)->ifindex));
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
NMPlatform *pl;
|
|
const char *path;
|
|
|
|
j = nmtst_get_rand_uint32() % 2;
|
|
|
|
if (nmtst_get_rand_uint32() % 2) {
|
|
pl = platform_1;
|
|
if (nmtst_get_rand_uint32() % 2)
|
|
path = "/proc/sys/net/ipv6/conf/dummy1_/disable_ipv6";
|
|
else
|
|
path = "/proc/sys/net/ipv6/conf/dummy2a/disable_ipv6";
|
|
} else {
|
|
pl = platform_2;
|
|
if (nmtst_get_rand_uint32() % 2)
|
|
path = "/proc/sys/net/ipv6/conf/dummy1_/disable_ipv6";
|
|
else
|
|
path = "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6";
|
|
}
|
|
g_assert(nm_platform_sysctl_set(pl,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(path),
|
|
nm_sprintf_buf(sbuf, "%d", j)));
|
|
_sysctl_assert_eq(pl, path, nm_sprintf_buf(sbuf, "%d", j));
|
|
}
|
|
|
|
_sysctl_assert_eq(platform_1, "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6", NULL);
|
|
_sysctl_assert_eq(platform_2, "/proc/sys/net/ipv6/conf/dummy2a/disable_ipv6", NULL);
|
|
|
|
/* Kernels prior to 3.19 dated 8 February, 2015 don't support ethtool -i for dummy devices.
|
|
* Work around that and skip asserts that are known to fail. */
|
|
ethtool_support = nmtstp_run_command("ethtool -i dummy1_ > /dev/null") == 0;
|
|
if (ethtool_support) {
|
|
g_assert(nmp_utils_ethtool_get_driver_info(
|
|
nmtstp_link_get_typed(platform_1, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex,
|
|
&driver_info));
|
|
g_assert(nmp_utils_ethtool_get_driver_info(
|
|
nmtstp_link_get_typed(platform_1, 0, "dummy2a", NM_LINK_TYPE_DUMMY)->ifindex,
|
|
&driver_info));
|
|
g_assert_cmpint(nmtstp_run_command("ethtool -i dummy1_ > /dev/null"), ==, 0);
|
|
g_assert_cmpint(nmtstp_run_command("ethtool -i dummy2a > /dev/null"), ==, 0);
|
|
g_assert_cmpint(nmtstp_run_command("ethtool -i dummy2b 2> /dev/null"), !=, 0);
|
|
}
|
|
|
|
g_assert(nm_platform_netns_push(platform_2, &netns_tmp));
|
|
|
|
if (ethtool_support) {
|
|
g_assert(nmp_utils_ethtool_get_driver_info(
|
|
nmtstp_link_get_typed(platform_2, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex,
|
|
&driver_info));
|
|
g_assert(nmp_utils_ethtool_get_driver_info(
|
|
nmtstp_link_get_typed(platform_2, 0, "dummy2b", NM_LINK_TYPE_DUMMY)->ifindex,
|
|
&driver_info));
|
|
g_assert_cmpint(nmtstp_run_command("ethtool -i dummy1_ > /dev/null"), ==, 0);
|
|
g_assert_cmpint(nmtstp_run_command("ethtool -i dummy2a 2> /dev/null"), !=, 0);
|
|
g_assert_cmpint(nmtstp_run_command("ethtool -i dummy2b > /dev/null"), ==, 0);
|
|
}
|
|
|
|
nmp_netns_pop(netns_tmp);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_netns_set_netns(gpointer fixture, gconstpointer test_data)
|
|
{
|
|
NMPlatform * platforms[3];
|
|
gs_unref_object NMPlatform *platform_0 = NULL;
|
|
gs_unref_object NMPlatform *platform_1 = NULL;
|
|
gs_unref_object NMPlatform *platform_2 = NULL;
|
|
nm_auto_pop_netns NMPNetns *netns_pop = NULL;
|
|
|
|
if (_test_netns_check_skip())
|
|
return;
|
|
|
|
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE);
|
|
platforms[1] = platform_1 = _test_netns_create_platform();
|
|
platforms[2] = platform_2 = _test_netns_create_platform();
|
|
|
|
nmtstp_netns_select_random(platforms, G_N_ELEMENTS(platforms), &netns_pop);
|
|
|
|
#define LINK_MOVE_NAME "link-move"
|
|
g_assert(!nm_platform_link_get_by_ifname(platform_1, LINK_MOVE_NAME));
|
|
g_assert(!nm_platform_link_get_by_ifname(platform_2, LINK_MOVE_NAME));
|
|
_ADD_DUMMY(platform_1, LINK_MOVE_NAME);
|
|
g_assert(nm_platform_link_get_by_ifname(platform_1, LINK_MOVE_NAME));
|
|
g_assert(!nm_platform_link_get_by_ifname(platform_2, LINK_MOVE_NAME));
|
|
g_assert(nm_platform_link_set_netns(
|
|
platform_1,
|
|
nm_platform_link_get_by_ifname(platform_1, LINK_MOVE_NAME)->ifindex,
|
|
nmp_netns_get_fd_net(nm_platform_netns_get(platform_2))));
|
|
g_assert(!nm_platform_link_get_by_ifname(platform_1, LINK_MOVE_NAME));
|
|
g_assert(!nm_platform_link_get_by_ifname(platform_2, LINK_MOVE_NAME));
|
|
nmtstp_assert_wait_for_link(platform_2, LINK_MOVE_NAME, NM_LINK_TYPE_DUMMY, 100);
|
|
g_assert(!nm_platform_link_get_by_ifname(platform_1, LINK_MOVE_NAME));
|
|
g_assert(nm_platform_link_get_by_ifname(platform_2, LINK_MOVE_NAME));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static char *
|
|
_get_current_namespace_id(int ns_type)
|
|
{
|
|
const char *p;
|
|
GError * error = NULL;
|
|
char * id;
|
|
|
|
switch (ns_type) {
|
|
case CLONE_NEWNET:
|
|
p = "/proc/self/ns/net";
|
|
break;
|
|
case CLONE_NEWNS:
|
|
p = "/proc/self/ns/mnt";
|
|
break;
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
id = g_file_read_link(p, &error);
|
|
g_assert_no_error(error);
|
|
g_assert(id);
|
|
return id;
|
|
}
|
|
|
|
static char *
|
|
_get_sysctl_value(const char *path)
|
|
{
|
|
char * data = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
|
|
if (!g_file_get_contents(path, &data, NULL, &error)) {
|
|
nmtst_assert_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, NULL);
|
|
g_assert(!data);
|
|
} else {
|
|
g_assert_no_error(error);
|
|
g_assert(data);
|
|
g_strstrip(data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_netns_push(gpointer fixture, gconstpointer test_data)
|
|
{
|
|
gs_unref_object NMPlatform *platform_0 = NULL;
|
|
gs_unref_object NMPlatform *platform_1 = NULL;
|
|
gs_unref_object NMPlatform *platform_2 = NULL;
|
|
nm_auto_pop_netns NMPNetns *netns_pop = NULL;
|
|
gs_unref_ptrarray GPtrArray *device_names = g_ptr_array_new_with_free_func(g_free);
|
|
int i, j;
|
|
const int ns_types_list[] = {CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWNET | CLONE_NEWNS};
|
|
const int ns_types_test[] = {CLONE_NEWNET, CLONE_NEWNS};
|
|
typedef struct {
|
|
NMPlatform *platform;
|
|
const char *device_name;
|
|
const char *sysctl_path;
|
|
const char *sysctl_value;
|
|
const char *ns_net;
|
|
const char *ns_mnt;
|
|
} PlatformData;
|
|
PlatformData pl[3] = {};
|
|
PlatformData *pl_base;
|
|
struct {
|
|
PlatformData *pl;
|
|
int ns_types;
|
|
} stack[6] = {};
|
|
int nstack;
|
|
|
|
if (_test_netns_check_skip())
|
|
return;
|
|
|
|
if (_check_sysctl_skip())
|
|
return;
|
|
|
|
pl[0].platform = platform_0 = nm_linux_platform_new(TRUE, TRUE);
|
|
pl[1].platform = platform_1 = _test_netns_create_platform();
|
|
pl[2].platform = platform_2 = _test_netns_create_platform();
|
|
|
|
pl_base = &pl[0];
|
|
i = nmtst_get_rand_uint32() % (G_N_ELEMENTS(pl) + 1);
|
|
if (i < G_N_ELEMENTS(pl)) {
|
|
pl_base = &pl[i];
|
|
g_assert(nm_platform_netns_push(pl[i].platform, &netns_pop));
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(pl); i++) {
|
|
nm_auto_pop_netns NMPNetns *netns_free = NULL;
|
|
char * tmp;
|
|
|
|
g_assert(nm_platform_netns_push(pl[i].platform, &netns_free));
|
|
|
|
tmp = g_strdup_printf("nmtst-dev-%d", i);
|
|
g_ptr_array_add(device_names, tmp);
|
|
pl[i].device_name = tmp;
|
|
|
|
tmp = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", pl[i].device_name);
|
|
g_ptr_array_add(device_names, tmp);
|
|
pl[i].sysctl_path = tmp;
|
|
|
|
pl[i].sysctl_value = nmtst_get_rand_uint32() % 2 ? "1" : "0";
|
|
|
|
_ADD_DUMMY(pl[i].platform, pl[i].device_name);
|
|
|
|
g_assert(nm_platform_sysctl_set(pl[i].platform,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(pl[i].sysctl_path),
|
|
pl[i].sysctl_value));
|
|
|
|
tmp = _get_current_namespace_id(CLONE_NEWNET);
|
|
g_ptr_array_add(device_names, tmp);
|
|
pl[i].ns_net = tmp;
|
|
|
|
tmp = _get_current_namespace_id(CLONE_NEWNS);
|
|
g_ptr_array_add(device_names, tmp);
|
|
pl[i].ns_mnt = tmp;
|
|
}
|
|
|
|
nstack = nmtst_get_rand_uint32() % (G_N_ELEMENTS(stack) + 1);
|
|
for (i = 0; i < nstack; i++) {
|
|
stack[i].pl = &pl[nmtst_get_rand_uint32() % G_N_ELEMENTS(pl)];
|
|
stack[i].ns_types = ns_types_list[nmtst_get_rand_uint32() % G_N_ELEMENTS(ns_types_list)];
|
|
|
|
nmp_netns_push_type(nm_platform_netns_get(stack[i].pl->platform), stack[i].ns_types);
|
|
}
|
|
|
|
/* pop some again. */
|
|
for (i = nmtst_get_rand_uint32() % (nstack + 1); i > 0; i--) {
|
|
g_assert(nstack > 0);
|
|
nstack--;
|
|
nmp_netns_pop(nm_platform_netns_get(stack[nstack].pl->platform));
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(ns_types_test); i++) {
|
|
int ns_type = ns_types_test[i];
|
|
PlatformData *p;
|
|
gs_free char *current_namespace_id = NULL;
|
|
|
|
p = pl_base;
|
|
for (j = nstack; j >= 1;) {
|
|
j--;
|
|
if (NM_FLAGS_ANY(stack[j].ns_types, ns_type)) {
|
|
p = stack[j].pl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
current_namespace_id = _get_current_namespace_id(ns_type);
|
|
|
|
if (ns_type == CLONE_NEWNET) {
|
|
g_assert_cmpstr(current_namespace_id, ==, p->ns_net);
|
|
for (j = 0; j < G_N_ELEMENTS(pl); j++) {
|
|
gs_free char *data = NULL;
|
|
|
|
if (p == &pl[j])
|
|
g_assert_cmpint(
|
|
nmtstp_run_command("ip link show %s 1>/dev/null", pl[j].device_name),
|
|
==,
|
|
0);
|
|
else
|
|
g_assert_cmpint(
|
|
nmtstp_run_command("ip link show %s 2>/dev/null", pl[j].device_name),
|
|
!=,
|
|
0);
|
|
|
|
data = _get_sysctl_value(pl[j].sysctl_path);
|
|
if (p == &pl[j])
|
|
g_assert_cmpstr(data, ==, pl[j].sysctl_value);
|
|
else
|
|
g_assert(!data);
|
|
}
|
|
} else if (ns_type == CLONE_NEWNS) {
|
|
g_assert_cmpstr(current_namespace_id, ==, p->ns_mnt);
|
|
for (j = 0; j < G_N_ELEMENTS(pl); j++) {
|
|
char path[600];
|
|
gs_free char *data = NULL;
|
|
|
|
nm_sprintf_buf(path, "/sys/devices/virtual/net/%s/ifindex", pl[j].device_name);
|
|
|
|
data = _get_sysctl_value(path);
|
|
if (p == &pl[j])
|
|
g_assert_cmpstr(data,
|
|
==,
|
|
nm_sprintf_buf(path,
|
|
"%d",
|
|
nmtstp_link_get_typed(p->platform,
|
|
0,
|
|
p->device_name,
|
|
NM_LINK_TYPE_DUMMY)
|
|
->ifindex));
|
|
else
|
|
g_assert(!data);
|
|
}
|
|
} else
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
for (i = nstack; i >= 1;) {
|
|
i--;
|
|
nmp_netns_pop(nm_platform_netns_get(stack[i].pl->platform));
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_netns_bind_to_path(gpointer fixture, gconstpointer test_data)
|
|
{
|
|
#define P_VAR_RUN "/run"
|
|
#define P_VAR_RUN_NETNS "/run/netns"
|
|
#define P_VAR_RUN_NETNS_BINDNAME "/run/netns/" P_NETNS_BINDNAME
|
|
#define P_NETNS_BINDNAME "nmtst-iproute2-netns"
|
|
gs_unref_object NMPlatform *platform_0 = NULL;
|
|
gs_unref_object NMPlatform *platform_1 = NULL;
|
|
gs_unref_object NMPlatform *platform_2 = NULL;
|
|
nm_auto_pop_netns NMPNetns *netns_pop = NULL;
|
|
NMPlatform * platforms[3];
|
|
NMPNetns * netns;
|
|
int i;
|
|
|
|
if (_test_netns_check_skip())
|
|
return;
|
|
|
|
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE);
|
|
platforms[1] = platform_1 = _test_netns_create_platform();
|
|
platforms[2] = platform_2 = _test_netns_create_platform();
|
|
|
|
nmtstp_netns_select_random(platforms, G_N_ELEMENTS(platforms), &netns_pop);
|
|
|
|
g_assert_cmpint(
|
|
mount("tmpfs", P_VAR_RUN, "tmpfs", MS_NOATIME | MS_NODEV | MS_NOSUID, "mode=0755,size=32K"),
|
|
==,
|
|
0);
|
|
g_assert_cmpint(mkdir(P_VAR_RUN_NETNS, 755), ==, 0);
|
|
|
|
i = (nmtst_get_rand_uint32() % 2) + 1;
|
|
netns = nm_platform_netns_get(platforms[i]);
|
|
|
|
_ADD_DUMMY(platforms[i], "dummy2b");
|
|
|
|
g_assert(!g_file_test(P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS));
|
|
g_assert_cmpint(nmtstp_run_command("ip netns exec " P_NETNS_BINDNAME " true 2>/dev/null"),
|
|
!=,
|
|
0);
|
|
|
|
g_assert(nmp_netns_bind_to_path(netns, P_VAR_RUN_NETNS_BINDNAME, NULL));
|
|
|
|
g_assert(g_file_test(P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS));
|
|
g_assert_cmpint(nmtstp_run_command("ip netns exec " P_NETNS_BINDNAME " true"), ==, 0);
|
|
g_assert_cmpint(
|
|
nmtstp_run_command("ip netns exec " P_NETNS_BINDNAME " ip link show dummy2b 1>/dev/null"),
|
|
==,
|
|
0);
|
|
|
|
g_assert(nmp_netns_bind_to_path_destroy(netns, P_VAR_RUN_NETNS_BINDNAME));
|
|
|
|
g_assert(!g_file_test(P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS));
|
|
g_assert_cmpint(nmtstp_run_command("ip netns exec " P_NETNS_BINDNAME " true 2>/dev/null"),
|
|
!=,
|
|
0);
|
|
|
|
g_assert_cmpint(umount(P_VAR_RUN), ==, 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_sysctl_rename(void)
|
|
{
|
|
NMPlatform *const PL = NM_PLATFORM_GET;
|
|
const char *const IFNAME[3] = {
|
|
"nm-dummy-0",
|
|
"nm-dummy-1",
|
|
"nm-dummy-2",
|
|
};
|
|
int ifindex[G_N_ELEMENTS(IFNAME)] = {0};
|
|
nm_auto_close int dirfd = -1;
|
|
int i;
|
|
char ifname_buf[IFNAMSIZ];
|
|
char * s;
|
|
const NMPlatformLink *pllink;
|
|
|
|
ifindex[0] = nmtstp_link_dummy_add(PL, -1, IFNAME[0])->ifindex;
|
|
ifindex[1] = nmtstp_link_dummy_add(PL, -1, IFNAME[1])->ifindex;
|
|
|
|
s = (nmtst_get_rand_uint32() % 2) ? NULL : ifname_buf;
|
|
|
|
if (nmtst_get_rand_uint32() % 2) {
|
|
/* bring the platform cache out of sync */
|
|
nmtstp_run_command_check("ip link set %s name %s", IFNAME[0], IFNAME[2]);
|
|
nm_platform_process_events(PL);
|
|
nmtstp_run_command_check("ip link set %s name %s", IFNAME[2], IFNAME[0]);
|
|
|
|
pllink = nm_platform_link_get_by_ifname(PL, IFNAME[2]);
|
|
g_assert(pllink && pllink->ifindex == ifindex[0]);
|
|
pllink = nm_platform_link_get_by_ifname(PL, IFNAME[0]);
|
|
g_assert(!pllink);
|
|
}
|
|
|
|
/* open dirfd for IFNAME[0] */
|
|
i = nmtst_get_rand_uint32() % (2 + G_N_ELEMENTS(IFNAME));
|
|
if (i == 0) {
|
|
dirfd = nm_platform_sysctl_open_netdir(PL, ifindex[0], s);
|
|
} else {
|
|
const char *ifname_guess;
|
|
|
|
/* provide a wrong or no guess. */
|
|
ifname_guess = i == 1 ? NULL : IFNAME[i - 2];
|
|
dirfd = nmp_utils_sysctl_open_netdir(ifindex[0], ifname_guess, s);
|
|
}
|
|
g_assert(dirfd >= 0);
|
|
if (s)
|
|
g_assert_cmpstr(s, ==, IFNAME[0]);
|
|
|
|
/* possibly rename the interfaces. */
|
|
switch (nmtst_get_rand_uint32() % 4) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
nmtstp_run_command_check("ip link set %s name %s", IFNAME[0], IFNAME[2]);
|
|
break;
|
|
case 2:
|
|
nmtstp_run_command_check("ip link set %s name %s", IFNAME[0], IFNAME[2]);
|
|
nmtstp_run_command_check("ip link set %s name %s", IFNAME[1], IFNAME[0]);
|
|
break;
|
|
}
|
|
|
|
/* possibly, resync platform cache (should make no difference). */
|
|
if (nmtst_get_rand_uint32() % 2)
|
|
nm_platform_process_events(PL);
|
|
|
|
/* check that we still read the same file. */
|
|
switch (nmtst_get_rand_uint32() % 2) {
|
|
case 0:
|
|
{
|
|
gs_free char *c = NULL;
|
|
|
|
if (!nm_utils_file_get_contents(dirfd,
|
|
"ifindex",
|
|
1 * 1024 * 1024,
|
|
NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
|
|
&c,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
g_assert_not_reached();
|
|
g_assert_cmpint(ifindex[0], ==, (int) _nm_utils_ascii_str_to_int64(c, 10, 0, G_MAXINT, -1));
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
g_assert_cmpint(ifindex[0],
|
|
==,
|
|
(gint32) nm_platform_sysctl_get_int32(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_NETDIR(dirfd, s ?: "<unknown>", "ifindex"),
|
|
-1));
|
|
break;
|
|
}
|
|
}
|
|
|
|
nm_platform_process_events(PL);
|
|
nmtstp_link_delete(PL, -1, ifindex[0], NULL, TRUE);
|
|
nmtstp_link_delete(PL, -1, ifindex[1], NULL, TRUE);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
test_sysctl_netns_switch(void)
|
|
{
|
|
const char *const IFNAME = "nm-dummy-0";
|
|
int ifindex, ifindex_tmp;
|
|
nm_auto_close int dirfd = -1;
|
|
char ifname_buf[IFNAMSIZ];
|
|
char * s;
|
|
gs_unref_object NMPlatform *platform_0 = NULL;
|
|
gs_unref_object NMPlatform *platform_1 = NULL;
|
|
gs_unref_object NMPlatform *platform_2 = NULL;
|
|
nm_auto_pop_netns NMPNetns *netns_pop_1 = NULL;
|
|
nm_auto_pop_netns NMPNetns *netns_pop_2 = NULL;
|
|
nm_auto_pop_netns NMPNetns *netns_pop_3 = NULL;
|
|
NMPlatform * PL;
|
|
NMPlatform * platforms[3];
|
|
|
|
if (_test_netns_check_skip())
|
|
return;
|
|
|
|
platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE);
|
|
platforms[1] = platform_1 = _test_netns_create_platform();
|
|
platforms[2] = platform_2 = _test_netns_create_platform();
|
|
PL = platforms[nmtst_get_rand_uint32() % 3];
|
|
|
|
nmtstp_netns_select_random(platforms, G_N_ELEMENTS(platforms), &netns_pop_1);
|
|
|
|
ifindex = nmtstp_link_dummy_add(PL, FALSE, IFNAME)->ifindex;
|
|
|
|
nmtstp_netns_select_random(platforms, G_N_ELEMENTS(platforms), &netns_pop_2);
|
|
|
|
s = (nmtst_get_rand_uint32() % 2) ? NULL : ifname_buf;
|
|
dirfd = nm_platform_sysctl_open_netdir(PL, ifindex, s);
|
|
g_assert(dirfd >= 0);
|
|
if (s)
|
|
g_assert_cmpstr(s, ==, IFNAME);
|
|
|
|
nmtstp_netns_select_random(platforms, G_N_ELEMENTS(platforms), &netns_pop_3);
|
|
|
|
/* even if we switch to other namespaces, we can still lookup the path correctly,
|
|
* either using dirfd or via the platform instance (which switches namespace as needed). */
|
|
{
|
|
gs_free char *c = NULL;
|
|
|
|
if (!nm_utils_file_get_contents(dirfd,
|
|
"ifindex",
|
|
0,
|
|
NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
|
|
&c,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
g_assert_not_reached();
|
|
g_assert_cmpint(ifindex, ==, (int) _nm_utils_ascii_str_to_int64(c, 10, 0, G_MAXINT, -1));
|
|
}
|
|
g_assert_cmpint(ifindex,
|
|
==,
|
|
(gint32) nm_platform_sysctl_get_int32(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_NETDIR(dirfd, s ?: "<unknown>", "ifindex"),
|
|
-1));
|
|
g_assert_cmpint(
|
|
ifindex,
|
|
==,
|
|
(gint32) nm_platform_sysctl_get_int32(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(nm_sprintf_bufa(100, "/sys/class/net/%s/ifindex", IFNAME)),
|
|
-1));
|
|
|
|
/* also test that nm_platform_sysctl_get() sets errno to ENOENT for non-existing paths. */
|
|
{
|
|
gint64 i64;
|
|
int errsv;
|
|
char * v;
|
|
|
|
errno = ESRCH;
|
|
v = nm_platform_sysctl_get(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE("/sys/devices/virtual/net/not-existing/ifindex"));
|
|
errsv = errno;
|
|
g_assert(!v);
|
|
g_assert_cmpint(errsv, ==, ENOENT);
|
|
|
|
errno = ESRCH;
|
|
i64 = nm_platform_sysctl_get_int_checked(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE("/sys/devices/virtual/net/not-existing/ifindex"),
|
|
10,
|
|
1,
|
|
G_MAXINT,
|
|
-1);
|
|
errsv = errno;
|
|
g_assert_cmpint(i64, ==, -1);
|
|
g_assert_cmpint(errsv, ==, ENOENT);
|
|
|
|
errno = ESRCH;
|
|
v = nm_platform_sysctl_get(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE("/sys/devices/virtual/net/lo/not-existing"));
|
|
errsv = errno;
|
|
g_assert(!v);
|
|
g_assert_cmpint(errsv, ==, ENOENT);
|
|
|
|
errno = ESRCH;
|
|
i64 = nm_platform_sysctl_get_int_checked(
|
|
PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE("/sys/devices/virtual/net/lo/not-existing"),
|
|
10,
|
|
1,
|
|
G_MAXINT,
|
|
-1);
|
|
errsv = errno;
|
|
g_assert_cmpint(i64, ==, -1);
|
|
g_assert_cmpint(errsv, ==, ENOENT);
|
|
}
|
|
|
|
/* accessing the path directly, only succeeds iff the current namespace happens to be the namespace
|
|
* in which we created the link. */
|
|
{
|
|
gs_free char *c = NULL;
|
|
|
|
if (!nm_utils_file_get_contents(-1,
|
|
nm_sprintf_bufa(100, "/sys/class/net/%s/ifindex", IFNAME),
|
|
0,
|
|
NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
|
|
&c,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
ifindex_tmp = -1;
|
|
else
|
|
ifindex_tmp = _nm_utils_ascii_str_to_int64(c, 10, 0, G_MAXINT, -2);
|
|
}
|
|
if (nmp_netns_get_current() == nm_platform_netns_get(PL))
|
|
g_assert_cmpint(ifindex_tmp, ==, ifindex);
|
|
else
|
|
g_assert_cmpint(ifindex_tmp, ==, -1);
|
|
|
|
nmtstp_link_delete(PL, FALSE, ifindex, NULL, TRUE);
|
|
}
|
|
|
|
typedef struct {
|
|
GMainLoop * loop;
|
|
const char *path;
|
|
gboolean expected_success;
|
|
gint32 expected_value;
|
|
} SetAsyncData;
|
|
|
|
static void
|
|
sysctl_set_async_cb(GError *error, gpointer user_data)
|
|
{
|
|
SetAsyncData *data = user_data;
|
|
|
|
if (data->expected_success) {
|
|
g_assert_no_error(error);
|
|
g_assert_cmpint(nm_platform_sysctl_get_int32(NM_PLATFORM_GET,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(data->path),
|
|
-1),
|
|
==,
|
|
data->expected_value);
|
|
} else
|
|
g_assert(error);
|
|
|
|
g_main_loop_quit(data->loop);
|
|
}
|
|
|
|
static void
|
|
test_sysctl_set_async(void)
|
|
{
|
|
NMPlatform *const PL = NM_PLATFORM_GET;
|
|
const char *const IFNAME = "nm-dummy-0";
|
|
const char *const PATH = "/proc/sys/net/ipv4/conf/nm-dummy-0/rp_filter";
|
|
GMainLoop * loop;
|
|
gs_unref_object GCancellable *cancellable = NULL;
|
|
gboolean proc_writable;
|
|
SetAsyncData data;
|
|
int ifindex;
|
|
|
|
ifindex = nmtstp_link_dummy_add(PL, -1, IFNAME)->ifindex;
|
|
loop = g_main_loop_new(NULL, FALSE);
|
|
cancellable = g_cancellable_new();
|
|
proc_writable = access(PATH, W_OK) == 0;
|
|
|
|
data = (SetAsyncData){
|
|
.loop = loop,
|
|
.path = PATH,
|
|
.expected_success = proc_writable,
|
|
.expected_value = 2,
|
|
};
|
|
|
|
nm_platform_sysctl_set_async(PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(PATH),
|
|
(const char *[]){"2", NULL},
|
|
sysctl_set_async_cb,
|
|
&data,
|
|
cancellable);
|
|
|
|
if (!nmtst_main_loop_run(loop, 1000))
|
|
g_assert_not_reached();
|
|
|
|
data = (SetAsyncData){
|
|
.loop = loop,
|
|
.path = PATH,
|
|
.expected_success = proc_writable,
|
|
.expected_value = 1,
|
|
};
|
|
|
|
nm_platform_sysctl_set_async(PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(PATH),
|
|
(const char *[]){"2", "0", "1", "0", "1", NULL},
|
|
sysctl_set_async_cb,
|
|
&data,
|
|
cancellable);
|
|
|
|
if (!nmtst_main_loop_run(loop, 2000))
|
|
g_assert_not_reached();
|
|
|
|
nmtstp_link_delete(NULL, -1, ifindex, IFNAME, TRUE);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
static void
|
|
test_sysctl_set_async_fail(void)
|
|
{
|
|
NMPlatform *const PL = NM_PLATFORM_GET;
|
|
const char *const IFNAME = "nm-dummy-0";
|
|
const char *const PATH = "/proc/sys/net/ipv4/conf/nm-dummy-0/does-not-exist";
|
|
GMainLoop * loop;
|
|
gs_unref_object GCancellable *cancellable = NULL;
|
|
SetAsyncData data;
|
|
int ifindex;
|
|
|
|
ifindex = nmtstp_link_dummy_add(PL, -1, IFNAME)->ifindex;
|
|
loop = g_main_loop_new(NULL, FALSE);
|
|
cancellable = g_cancellable_new();
|
|
|
|
data = (SetAsyncData){
|
|
.loop = loop,
|
|
.path = PATH,
|
|
.expected_success = FALSE,
|
|
};
|
|
|
|
nm_platform_sysctl_set_async(PL,
|
|
NMP_SYSCTL_PATHID_ABSOLUTE(PATH),
|
|
(const char *[]){"2", NULL},
|
|
sysctl_set_async_cb,
|
|
&data,
|
|
cancellable);
|
|
|
|
if (!nmtst_main_loop_run(loop, 1000))
|
|
g_assert_not_reached();
|
|
|
|
nmtstp_link_delete(NULL, -1, ifindex, IFNAME, TRUE);
|
|
g_main_loop_unref(loop);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static gpointer
|
|
_test_netns_mt_thread(gpointer data)
|
|
{
|
|
NMPNetns * netns1 = data;
|
|
gs_unref_object NMPNetns *netns2 = NULL;
|
|
NMPNetns * netns_bottom;
|
|
NMPNetns * initial;
|
|
|
|
netns_bottom = nmp_netns_get_initial();
|
|
g_assert(netns_bottom);
|
|
|
|
/* I don't know why, but we need to create a new netns here at least once.
|
|
* Otherwise, setns(, CLONE_NEWNS) below fails with EINVAL (???).
|
|
*
|
|
* Something is not right here, but what? */
|
|
netns2 = nmp_netns_new();
|
|
nmp_netns_pop(netns2);
|
|
g_clear_object(&netns2);
|
|
|
|
nmp_netns_push(netns1);
|
|
nmp_netns_push_type(netns_bottom, CLONE_NEWNET);
|
|
nmp_netns_push_type(netns_bottom, CLONE_NEWNS);
|
|
nmp_netns_push_type(netns1, CLONE_NEWNS);
|
|
nmp_netns_pop(netns1);
|
|
nmp_netns_pop(netns_bottom);
|
|
nmp_netns_pop(netns_bottom);
|
|
nmp_netns_pop(netns1);
|
|
|
|
initial = nmp_netns_get_initial();
|
|
g_assert(NMP_IS_NETNS(initial));
|
|
return g_object_ref(initial);
|
|
}
|
|
|
|
static void
|
|
test_netns_mt(void)
|
|
{
|
|
gs_unref_object NMPNetns *netns1 = NULL;
|
|
NMPNetns * initial_from_other_thread;
|
|
GThread * th;
|
|
|
|
if (_test_netns_check_skip())
|
|
return;
|
|
|
|
netns1 = nmp_netns_new();
|
|
g_assert(NMP_NETNS(netns1));
|
|
nmp_netns_pop(netns1);
|
|
|
|
th = g_thread_new("nm-test-netns-mt", _test_netns_mt_thread, netns1);
|
|
initial_from_other_thread = g_thread_join(th);
|
|
g_assert(NMP_IS_NETNS(initial_from_other_thread));
|
|
|
|
if (nmtst_get_rand_bool()) {
|
|
nmp_netns_push(initial_from_other_thread);
|
|
nmp_netns_pop(initial_from_other_thread);
|
|
}
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(initial_from_other_thread),
|
|
(gpointer *) &initial_from_other_thread);
|
|
g_object_unref(initial_from_other_thread);
|
|
g_assert(initial_from_other_thread == NULL);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
ethtool_features_dump(const NMEthtoolFeatureStates *features)
|
|
{
|
|
guint i, j;
|
|
|
|
g_assert(features);
|
|
|
|
_LOGT(">>> %u features (%u ss-features)", features->n_states, features->n_ss_features);
|
|
|
|
for (i = 0; i < features->n_states; i++) {
|
|
const NMEthtoolFeatureState *s = &features->states_list[i];
|
|
|
|
_LOGT(">>> feature-list[%3u]: %3d = %-32s (%3u) | %s %s %s %s",
|
|
i,
|
|
(int) s->info->ethtool_id,
|
|
s->info->kernel_names[s->idx_kernel_name],
|
|
s->idx_ss_features,
|
|
s->active ? "ACT" : "act",
|
|
s->available ? "AVA" : "ava",
|
|
s->never_changed ? "NCH" : "nch",
|
|
s->requested ? "REQ" : "req");
|
|
}
|
|
for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) {
|
|
_LOGT(">>> feature-idx [%3u]: %-32s = %u features",
|
|
i + (guint) _NM_ETHTOOL_ID_FEATURE_FIRST,
|
|
nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
|
|
(guint) NM_PTRARRAY_LEN(features->states_indexed[i]));
|
|
for (j = 0; features->states_indexed[i] && features->states_indexed[i][j]; j++) {
|
|
const NMEthtoolFeatureState *s = features->states_indexed[i][j];
|
|
|
|
_LOGT(">>> %3u: %-32s | %s %s %s %s",
|
|
j,
|
|
s->info->kernel_names[s->idx_kernel_name],
|
|
s->active ? "ACT" : "act",
|
|
s->available ? "AVA" : "ava",
|
|
s->never_changed ? "NCH" : "nch",
|
|
s->requested ? "REQ" : "req");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_ethtool_features_get(void)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *gfree_keeper = g_ptr_array_new_with_free_func(g_free);
|
|
const int IFINDEX = 1;
|
|
guint i;
|
|
guint i_run;
|
|
|
|
for (i_run = 0; i_run < 5; i_run++) {
|
|
NMEthtoolFeatureStates *features;
|
|
NMTernary * requested;
|
|
gboolean do_set = TRUE;
|
|
|
|
requested = g_new(NMTernary, _NM_ETHTOOL_ID_FEATURE_NUM);
|
|
for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++)
|
|
requested[i] = NM_TERNARY_DEFAULT;
|
|
g_ptr_array_add(gfree_keeper, requested);
|
|
|
|
if (i_run == 0) {
|
|
requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(NM_ETHTOOL_ID_FEATURE_RX)] = NM_TERNARY_FALSE;
|
|
requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(NM_ETHTOOL_ID_FEATURE_TSO)] = NM_TERNARY_FALSE;
|
|
requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION)] =
|
|
NM_TERNARY_FALSE;
|
|
} else if (i_run == 1)
|
|
do_set = FALSE;
|
|
else if (i_run == 2) {
|
|
requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(NM_ETHTOOL_ID_FEATURE_TSO)] = NM_TERNARY_FALSE;
|
|
requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION)] =
|
|
NM_TERNARY_TRUE;
|
|
} else if (i_run == 3)
|
|
do_set = FALSE;
|
|
|
|
_LOGT(">>> ethtool-features-get RUN %u (do-set=%s", i_run, do_set ? "set" : "reset");
|
|
|
|
features = nmp_utils_ethtool_get_features(IFINDEX);
|
|
g_ptr_array_add(gfree_keeper, features);
|
|
|
|
ethtool_features_dump(features);
|
|
|
|
if (_LOGT_ENABLED())
|
|
_system("ethtool -k lo");
|
|
|
|
if (!do_set) {
|
|
requested = gfree_keeper->pdata[i_run * 2 - 2];
|
|
features = gfree_keeper->pdata[i_run * 2 - 1];
|
|
}
|
|
|
|
nmp_utils_ethtool_set_features(IFINDEX, features, requested, do_set);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
|
|
|
|
void
|
|
_nmtstp_init_tests(int *argc, char ***argv)
|
|
{
|
|
nmtst_init_with_logging(argc, argv, NULL, "ALL");
|
|
}
|
|
|
|
void
|
|
_nmtstp_setup_tests(void)
|
|
{
|
|
nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, DEVICE_NAME, FALSE);
|
|
nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, SLAVE_NAME, FALSE);
|
|
nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, PARENT_NAME, FALSE);
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, DEVICE_NAME));
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, SLAVE_NAME));
|
|
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, PARENT_NAME));
|
|
|
|
g_test_add_func("/link/bogus", test_bogus);
|
|
g_test_add_func("/link/loopback", test_loopback);
|
|
g_test_add_func("/link/internal", test_internal);
|
|
g_test_add_func("/link/software/bridge", test_bridge);
|
|
g_test_add_func("/link/software/bond", test_bond);
|
|
g_test_add_func("/link/software/team", test_team);
|
|
g_test_add_func("/link/software/vlan", test_vlan);
|
|
g_test_add_func("/link/software/bridge/addr", test_bridge_addr);
|
|
|
|
if (nmtstp_is_root_test()) {
|
|
g_test_add_func("/link/external", test_external);
|
|
|
|
test_software_detect_add("/link/software/detect/bridge", NM_LINK_TYPE_BRIDGE, 0);
|
|
test_software_detect_add("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0);
|
|
test_software_detect_add("/link/software/detect/gretap", NM_LINK_TYPE_GRETAP, 0);
|
|
test_software_detect_add("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0);
|
|
test_software_detect_add("/link/software/detect/ip6tnl/1", NM_LINK_TYPE_IP6TNL, 1);
|
|
test_software_detect_add("/link/software/detect/ip6gre", NM_LINK_TYPE_IP6GRE, 0);
|
|
test_software_detect_add("/link/software/detect/ip6gretap", NM_LINK_TYPE_IP6GRETAP, 0);
|
|
test_software_detect_add("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0);
|
|
test_software_detect_add("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
|
|
test_software_detect_add("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0);
|
|
test_software_detect_add("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0);
|
|
test_software_detect_add("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0);
|
|
test_software_detect_add("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
|
|
test_software_detect_add("/link/software/detect/vrf", NM_LINK_TYPE_VRF, 0);
|
|
test_software_detect_add("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
|
|
test_software_detect_add("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
|
|
test_software_detect_add("/link/software/detect/wireguard/0", NM_LINK_TYPE_WIREGUARD, 0);
|
|
test_software_detect_add("/link/software/detect/wireguard/1", NM_LINK_TYPE_WIREGUARD, 1);
|
|
test_software_detect_add("/link/software/detect/wireguard/2", NM_LINK_TYPE_WIREGUARD, 2);
|
|
|
|
g_test_add_func("/link/software/vlan/set-xgress", test_vlan_set_xgress);
|
|
|
|
g_test_add_data_func("/link/create-many-links/20",
|
|
GUINT_TO_POINTER(20),
|
|
test_create_many_links);
|
|
g_test_add_data_func("/link/create-many-links/1000",
|
|
GUINT_TO_POINTER(1000),
|
|
test_create_many_links);
|
|
|
|
g_test_add_func("/link/nl-bugs/veth", test_nl_bugs_veth);
|
|
g_test_add_func("/link/nl-bugs/spurious-newlink", test_nl_bugs_spuroius_newlink);
|
|
g_test_add_func("/link/nl-bugs/spurious-dellink", test_nl_bugs_spuroius_dellink);
|
|
|
|
g_test_add_vtable("/general/netns/general",
|
|
0,
|
|
NULL,
|
|
_test_netns_setup,
|
|
test_netns_general,
|
|
_test_netns_teardown);
|
|
g_test_add_vtable("/general/netns/set-netns",
|
|
0,
|
|
NULL,
|
|
_test_netns_setup,
|
|
test_netns_set_netns,
|
|
_test_netns_teardown);
|
|
g_test_add_vtable("/general/netns/push",
|
|
0,
|
|
NULL,
|
|
_test_netns_setup,
|
|
test_netns_push,
|
|
_test_netns_teardown);
|
|
g_test_add_vtable("/general/netns/bind-to-path",
|
|
0,
|
|
NULL,
|
|
_test_netns_setup,
|
|
test_netns_bind_to_path,
|
|
_test_netns_teardown);
|
|
|
|
g_test_add_func("/general/netns/mt", test_netns_mt);
|
|
|
|
g_test_add_func("/general/sysctl/rename", test_sysctl_rename);
|
|
g_test_add_func("/general/sysctl/netns-switch", test_sysctl_netns_switch);
|
|
g_test_add_func("/general/sysctl/set-async", test_sysctl_set_async);
|
|
g_test_add_func("/general/sysctl/set-async-fail", test_sysctl_set_async_fail);
|
|
|
|
g_test_add_func("/link/ethtool/features/get", test_ethtool_features_get);
|
|
}
|
|
}
|