platform: support switching partial namespaces

Previously, the push/pop API to switch between namespaces would always
switch both the net and mount namespace together.

There are situations, where we want to only switch one namespace.
For example, the function nmp_netns_bind_to_path() introduced next
only wants to switch the net namespace to get /proc/self/ns/net,
but must not switch the mount namespace as it bind-mounds in the
namespace of the caller.
This commit is contained in:
Thomas Haller
2016-03-14 14:20:33 +01:00
parent a0cce2b195
commit 3428d8607d
3 changed files with 387 additions and 43 deletions

View File

@@ -30,6 +30,37 @@
#define PROC_SELF_NS_MNT "/proc/self/ns/mnt" #define PROC_SELF_NS_MNT "/proc/self/ns/mnt"
#define PROC_SELF_NS_NET "/proc/self/ns/net" #define PROC_SELF_NS_NET "/proc/self/ns/net"
#define _CLONE_NS_ALL ((int) (CLONE_NEWNS | CLONE_NEWNET))
#define _CLONE_NS_ALL_V CLONE_NEWNS , CLONE_NEWNET
NM_UTILS_FLAGS2STR_DEFINE_STATIC (_clone_ns_to_str, int,
NM_UTILS_FLAGS2STR (CLONE_NEWNS, "mnt"),
NM_UTILS_FLAGS2STR (CLONE_NEWNET, "net"),
);
static const char *
__ns_types_to_str (int ns_types, int ns_types_already_set, char *buf, gsize len)
{
const char *b = buf;
char bb[200];
nm_utils_strbuf_append_c (&buf, &len, '[');
if (ns_types & ~ns_types_already_set) {
nm_utils_strbuf_append_str (&buf, &len,
_clone_ns_to_str (ns_types & ~ns_types_already_set, bb, sizeof (bb)));
}
if (ns_types & ns_types_already_set) {
if (ns_types & ~ns_types_already_set)
nm_utils_strbuf_append_c (&buf, &len, '/');
nm_utils_strbuf_append_str (&buf, &len,
_clone_ns_to_str (ns_types & ns_types_already_set, bb, sizeof (bb)));
}
nm_utils_strbuf_append_c (&buf, &len, ']');
return b;
}
#define _ns_types_to_str(ns_types, ns_types_already_set, buf) \
__ns_types_to_str (ns_types, ns_types_already_set, buf, sizeof (buf))
/*********************************************************************************************/ /*********************************************************************************************/
#define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG_DOMAIN LOGD_PLATFORM
@@ -67,9 +98,10 @@ struct _NMPNetnsPrivate {
typedef struct { typedef struct {
NMPNetns *netns; NMPNetns *netns;
int count; int count;
int ns_types;
} NetnsInfo; } NetnsInfo;
static void _stack_push (NMPNetns *netns); static void _stack_push (NMPNetns *netns, int ns_types);
static NMPNetns *_netns_new (GError **error); static NMPNetns *_netns_new (GError **error);
/*********************************************************************************************/ /*********************************************************************************************/
@@ -98,7 +130,7 @@ _stack_ensure_init_impl (void)
return; return;
} }
_stack_push (netns); _stack_push (netns, _CLONE_NS_ALL);
/* we leak this instance inside netns_stack. It cannot be popped. */ /* we leak this instance inside netns_stack. It cannot be popped. */
g_object_unref (netns); g_object_unref (netns);
@@ -110,6 +142,60 @@ _stack_ensure_init_impl (void)
} \ } \
} G_STMT_END } G_STMT_END
static NMPNetns *
_stack_current_netns (int ns_types)
{
guint j;
nm_assert (netns_stack && netns_stack->len > 0);
/* we search the stack top-down to find the netns that has
* all @ns_types set. */
for (j = netns_stack->len; ns_types && j >= 1; ) {
NetnsInfo *info;
info = &g_array_index (netns_stack, NetnsInfo, --j);
if (NM_FLAGS_ALL (info->ns_types, ns_types))
return info->netns;
}
g_return_val_if_reached (NULL);
}
static int
_stack_current_ns_types (NMPNetns *netns, int ns_types)
{
const int ns_types_check[] = { _CLONE_NS_ALL_V };
guint i, j;
int res = 0;
nm_assert (netns);
nm_assert (netns_stack && netns_stack->len > 0);
/* we search the stack top-down to check which of @ns_types
* are already set to @netns. */
for (j = netns_stack->len; ns_types && j >= 1; ) {
NetnsInfo *info;
info = &g_array_index (netns_stack, NetnsInfo, --j);
if (info->netns != netns) {
ns_types = NM_FLAGS_UNSET (ns_types, info->ns_types);
continue;
}
for (i = 0; i < G_N_ELEMENTS (ns_types_check); i++) {
if ( NM_FLAGS_HAS (ns_types, ns_types_check[i])
&& NM_FLAGS_HAS (info->ns_types, ns_types_check[i])) {
res = NM_FLAGS_SET (res, ns_types_check[i]);
ns_types = NM_FLAGS_UNSET (ns_types, ns_types_check[i]);
}
}
}
return res;
}
static NetnsInfo * static NetnsInfo *
_stack_peek (void) _stack_peek (void)
{ {
@@ -120,16 +206,6 @@ _stack_peek (void)
return NULL; return NULL;
} }
static NetnsInfo *
_stack_peek2 (void)
{
nm_assert (netns_stack);
if (netns_stack->len > 1)
return &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 2));
return NULL;
}
static NetnsInfo * static NetnsInfo *
_stack_bottom (void) _stack_bottom (void)
{ {
@@ -141,17 +217,20 @@ _stack_bottom (void)
} }
static void static void
_stack_push (NMPNetns *netns) _stack_push (NMPNetns *netns, int ns_types)
{ {
NetnsInfo *info; NetnsInfo *info;
nm_assert (netns_stack); nm_assert (netns_stack);
nm_assert (NMP_IS_NETNS (netns)); nm_assert (NMP_IS_NETNS (netns));
nm_assert (NM_FLAGS_ANY (ns_types, _CLONE_NS_ALL));
nm_assert (!NM_FLAGS_ANY (ns_types, ~_CLONE_NS_ALL));
g_array_set_size (netns_stack, netns_stack->len + 1); g_array_set_size (netns_stack, netns_stack->len + 1);
info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1)); info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1));
info->netns = g_object_ref (netns); info->netns = g_object_ref (netns);
info->ns_types = ns_types;
info->count = 1; info->count = 1;
} }
@@ -225,25 +304,47 @@ _netns_new (GError **error)
return self; return self;
} }
static int
_setns (NMPNetns *self, int type)
{
char buf[100];
int fd;
nm_assert (NM_IN_SET (type, _CLONE_NS_ALL_V));
fd = (type == CLONE_NEWNET) ? self->priv->fd_net : self->priv->fd_mnt;
_LOGt (self, "set netns(%s, %d)", _ns_types_to_str (type, 0, buf), fd);
return setns (fd, type);
}
static gboolean static gboolean
_netns_switch (NMPNetns *self, NMPNetns *netns_fail) _netns_switch_push (NMPNetns *self, int ns_types)
{ {
int errsv; int errsv;
if (setns (self->priv->fd_net, CLONE_NEWNET) != 0) { if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET)
&& !_stack_current_ns_types (self, CLONE_NEWNET)
&& _setns (self, CLONE_NEWNET) != 0) {
errsv = errno; errsv = errno;
_LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); _LOGE (self, "failed to switch netns: %s", g_strerror (errsv));
return FALSE; return FALSE;
} }
if (setns (self->priv->fd_mnt, CLONE_NEWNS) != 0) { if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS)
&& !_stack_current_ns_types (self, CLONE_NEWNS)
&& _setns (self, CLONE_NEWNS) != 0) {
errsv = errno; errsv = errno;
_LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv));
/* try to fix the mess by returning to the previous netns. */ /* try to fix the mess by returning to the previous netns. */
if (netns_fail) { if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET)
if (setns (netns_fail->priv->fd_net, CLONE_NEWNET) != 0) { && !_stack_current_ns_types (self, CLONE_NEWNET)) {
self = _stack_current_netns (CLONE_NEWNET);
if ( self
&& _setns (self, CLONE_NEWNET) != 0) {
errsv = errno; errsv = errno;
_LOGE (netns_fail, "failed to restore netns: %s", g_strerror (errsv)); _LOGE (self, "failed to restore netns: %s", g_strerror (errsv));
} }
} }
return FALSE; return FALSE;
@@ -252,6 +353,41 @@ _netns_switch (NMPNetns *self, NMPNetns *netns_fail)
return TRUE; return TRUE;
} }
static gboolean
_netns_switch_pop (NMPNetns *self, int ns_types)
{
int errsv;
NMPNetns *current;
int success = TRUE;
if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET)
&& (!self || !_stack_current_ns_types (self, CLONE_NEWNET))) {
current = _stack_current_netns (CLONE_NEWNET);
if (!current) {
g_warn_if_reached ();
success = FALSE;
} else if (_setns (current, CLONE_NEWNET) != 0) {
errsv = errno;
_LOGE (self, "failed to switch netns: %s", g_strerror (errsv));
success = FALSE;
}
}
if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS)
&& (!self || !_stack_current_ns_types (self, CLONE_NEWNS))) {
current = _stack_current_netns (CLONE_NEWNS);
if (!current) {
g_warn_if_reached ();
success = FALSE;
} else if (_setns (current, CLONE_NEWNS) != 0) {
errsv = errno;
_LOGE (self, "failed to switch mntns: %s", g_strerror (errsv));
success = FALSE;
}
}
return success;
}
/*********************************************************************************************/ /*********************************************************************************************/
int int
@@ -272,37 +408,58 @@ nmp_netns_get_fd_mnt (NMPNetns *self)
/*********************************************************************************************/ /*********************************************************************************************/
gboolean static gboolean
nmp_netns_push (NMPNetns *self) _nmp_netns_push_type (NMPNetns *self, int ns_types)
{ {
NetnsInfo *info; NetnsInfo *info;
char sbuf[100];
g_return_val_if_fail (NMP_IS_NETNS (self), FALSE);
_stack_ensure_init (); _stack_ensure_init ();
info = _stack_peek (); info = _stack_peek ();
g_return_val_if_fail (info, FALSE); g_return_val_if_fail (info, FALSE);
if (info->netns == self) { if (info->netns == self && info->ns_types == ns_types) {
info->count++; info->count++;
_LOGt (self, "push (increase count to %d)", info->count); _LOGt (self, "push#%u* %s (increase count to %d)",
_stack_size () - 1,
_ns_types_to_str (ns_types, ns_types, sbuf), info->count);
return TRUE; return TRUE;
} }
_LOGD (self, "push (was %p)", info->netns); _LOGD (self, "push#%u %s",
_stack_size (),
_ns_types_to_str (ns_types,
_stack_current_ns_types (self, ns_types),
sbuf));
if (!_netns_switch (self, info->netns)) if (!_netns_switch_push (self, ns_types))
return FALSE; return FALSE;
_stack_push (self); _stack_push (self, ns_types);
return TRUE; return TRUE;
} }
gboolean
nmp_netns_push (NMPNetns *self)
{
g_return_val_if_fail (NMP_IS_NETNS (self), FALSE);
return _nmp_netns_push_type (self, _CLONE_NS_ALL);
}
gboolean
nmp_netns_push_type (NMPNetns *self, int ns_types)
{
g_return_val_if_fail (NMP_IS_NETNS (self), FALSE);
g_return_val_if_fail (!NM_FLAGS_ANY (ns_types, ~_CLONE_NS_ALL), FALSE);
return _nmp_netns_push_type (self, ns_types == 0 ? _CLONE_NS_ALL : ns_types);
}
NMPNetns * NMPNetns *
nmp_netns_new (void) nmp_netns_new (void)
{ {
NetnsInfo *info;
NMPNetns *self; NMPNetns *self;
int errsv; int errsv;
GError *error = NULL; GError *error = NULL;
@@ -315,7 +472,7 @@ nmp_netns_new (void)
return NULL; return NULL;
} }
if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) { if (unshare (_CLONE_NS_ALL) != 0) {
errsv = errno; errsv = errno;
_LOGE (NULL, "failed to create new net and mnt namespace: %s", g_strerror (errsv)); _LOGE (NULL, "failed to create new net and mnt namespace: %s", g_strerror (errsv));
return NULL; return NULL;
@@ -346,12 +503,11 @@ nmp_netns_new (void)
goto err_out; goto err_out;
} }
_stack_push (self); _stack_push (self, _CLONE_NS_ALL);
return self; return self;
err_out: err_out:
info = _stack_peek (); _netns_switch_pop (NULL, _CLONE_NS_ALL);
_netns_switch (info->netns, NULL);
return NULL; return NULL;
} }
@@ -359,6 +515,7 @@ gboolean
nmp_netns_pop (NMPNetns *self) nmp_netns_pop (NMPNetns *self)
{ {
NetnsInfo *info; NetnsInfo *info;
int ns_types;
g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); g_return_val_if_fail (NMP_IS_NETNS (self), FALSE);
@@ -371,7 +528,8 @@ nmp_netns_pop (NMPNetns *self)
if (info->count > 1) { if (info->count > 1) {
info->count--; info->count--;
_LOGt (self, "pop (decrease count to %d)", info->count); _LOGt (self, "pop#%u* (decrease count to %d)",
_stack_size () - 1, info->count);
return TRUE; return TRUE;
} }
g_return_val_if_fail (info->count == 1, FALSE); g_return_val_if_fail (info->count == 1, FALSE);
@@ -379,14 +537,13 @@ nmp_netns_pop (NMPNetns *self)
/* cannot pop the original netns. */ /* cannot pop the original netns. */
g_return_val_if_fail (_stack_size () > 1, FALSE); g_return_val_if_fail (_stack_size () > 1, FALSE);
_LOGD (self, "pop (restore %p)", _stack_peek2 ()); _LOGD (self, "pop#%u", _stack_size () - 1);
ns_types = info->ns_types;
_stack_pop (); _stack_pop ();
info = _stack_peek ();
nm_assert (info); return _netns_switch_pop (self, ns_types);
return _netns_switch (info->netns, NULL);
} }
NMPNetns * NMPNetns *

View File

@@ -49,6 +49,7 @@ GType nmp_netns_get_type (void);
NMPNetns *nmp_netns_new (void); NMPNetns *nmp_netns_new (void);
gboolean nmp_netns_push (NMPNetns *self); gboolean nmp_netns_push (NMPNetns *self);
gboolean nmp_netns_push_type (NMPNetns *self, int ns_types);
gboolean nmp_netns_pop (NMPNetns *self); gboolean nmp_netns_pop (NMPNetns *self);
NMPNetns *nmp_netns_get_current (void); NMPNetns *nmp_netns_get_current (void);

View File

@@ -1951,13 +1951,13 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
_ADD_DUMMY (p, nm_sprintf_buf (sbuf, "other-c-%s-%02d", id, i)); _ADD_DUMMY (p, nm_sprintf_buf (sbuf, "other-c-%s-%02d", id, i));
} }
g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy1_/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nm_platform_link_get_by_ifname (platform_1, "dummy1_")->ifindex)); g_assert_cmpstr (nm_platform_sysctl_get (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));
g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nm_platform_link_get_by_ifname (platform_1, "dummy2a")->ifindex)); g_assert_cmpstr (nm_platform_sysctl_get (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));
g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, NULL); g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, NULL);
g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy1_/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nm_platform_link_get_by_ifname (platform_2, "dummy1_")->ifindex)); g_assert_cmpstr (nm_platform_sysctl_get (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));
g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, NULL); g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, NULL);
g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nm_platform_link_get_by_ifname (platform_2, "dummy2b")->ifindex)); g_assert_cmpstr (nm_platform_sysctl_get (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++) { for (i = 0; i < 10; i++) {
NMPlatform *pl; NMPlatform *pl;
@@ -2051,6 +2051,191 @@ test_netns_set_netns (gpointer fixture, gconstpointer test_data)
/*****************************************************************************/ /*****************************************************************************/
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;
pl[0].platform = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
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_int () % (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_int () % 2 ? "1" : "0";
_ADD_DUMMY (pl[i].platform, pl[i].device_name);
g_assert (nm_platform_sysctl_set (pl[i].platform, 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_int () % (G_N_ELEMENTS (stack) + 1);
for (i = 0; i < nstack; i++) {
stack[i].pl = &pl[nmtst_get_rand_int () % G_N_ELEMENTS (pl)];
stack[i].ns_types = ns_types_list[nmtst_get_rand_int () % 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_int () % (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_HAS (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));
}
}
/*****************************************************************************/
void void
init_tests (int *argc, char ***argv) init_tests (int *argc, char ***argv)
{ {
@@ -2100,5 +2285,6 @@ setup_tests (void)
g_test_add_vtable ("/general/netns/general", 0, NULL, _test_netns_setup, test_netns_general, _test_netns_teardown); 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/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);
} }
} }