Commit b2b73809 authored by Thomas Haller's avatar Thomas Haller

platform: merge branch 'th/platform-netns-bgo762408'

https://bugzilla.gnome.org/show_bug.cgi?id=762408
parents 6165df78 c7b38625
......@@ -311,6 +311,8 @@ libNetworkManager_la_SOURCES = \
dnsmasq-manager/nm-dnsmasq-utils.c \
dnsmasq-manager/nm-dnsmasq-utils.h \
\
platform/nmp-netns.c \
platform/nmp-netns.h \
platform/nm-fake-platform.c \
platform/nm-fake-platform.h \
platform/nm-linux-platform.c \
......@@ -541,6 +543,8 @@ libnm_iface_helper_la_SOURCES = \
platform/nm-platform.h \
platform/nm-platform-utils.c \
platform/nm-platform-utils.h \
platform/nmp-netns.c \
platform/nmp-netns.h \
platform/nmp-object.c \
platform/nmp-object.h \
platform/wifi/wifi-utils-nl80211.c \
......
......@@ -79,7 +79,7 @@ typedef struct _NMPlatformIP4Route NMPlatformIP4Route;
typedef struct _NMPlatformIP6Address NMPlatformIP6Address;
typedef struct _NMPlatformIP6Route NMPlatformIP6Route;
typedef struct _NMPlatformLink NMPlatformLink;
typedef struct _NMPNetns NMPNetns;
typedef struct _NMPObject NMPObject;
typedef enum {
......
This diff is collapsed.
......@@ -41,6 +41,7 @@
#include "nm-enum-types.h"
#include "nm-platform-utils.h"
#include "nmp-object.h"
#include "nmp-netns.h"
/*****************************************************************************/
......@@ -89,6 +90,7 @@ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 };
enum {
PROP_0,
PROP_NETNS_SUPPORT,
PROP_REGISTER_SINGLETON,
LAST_PROP,
};
......@@ -2128,6 +2130,10 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe
/* Pre-4.1 kernel did not expose the peer_ifindex as IFA_LINK. Lookup via ethtool. */
if (out_peer_ifindex) {
nm_auto_pop_netns NMPNetns *netns = NULL;
if (!nm_platform_netns_push (self, &netns))
return FALSE;
peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (plink->name);
if (peer_ifindex <= 0)
return FALSE;
......@@ -2393,16 +2399,24 @@ _to_string_ifa_flags (guint32 ifa_flags, char *buf, gsize size)
gboolean
nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
_CHECK_SELF (self, klass, FALSE);
if (!nm_platform_netns_push (self, &netns))
return FALSE;
return nmp_utils_ethtool_set_wake_on_lan (ifname, wol, wol_password);
}
gboolean
nm_platform_ethtool_get_link_speed (NMPlatform *self, const char *ifname, guint32 *out_speed)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
_CHECK_SELF (self, klass, FALSE);
if (!nm_platform_netns_push (self, &netns))
return FALSE;
return nmp_utils_ethtool_get_link_speed (ifname, out_speed);
}
......@@ -4018,6 +4032,31 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform
/******************************************************************/
NMPNetns *
nm_platform_netns_get (NMPlatform *self)
{
_CHECK_SELF (self, klass, NULL);
return self->_netns;
}
gboolean
nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns)
{
g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE);
if ( platform->_netns
&& !nmp_netns_push (platform->_netns)) {
NM_SET_OUT (netns, NULL);
return FALSE;
}
NM_SET_OUT (netns, platform->_netns);
return TRUE;
}
/******************************************************************/
static gboolean
_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric)
{
......@@ -4117,9 +4156,20 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (object);
NMPlatform *self = NM_PLATFORM (object);
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
switch (prop_id) {
case PROP_NETNS_SUPPORT:
/* construct-only */
if (g_value_get_boolean (value)) {
NMPNetns *netns;
netns = nmp_netns_get_current ();
if (netns)
self->_netns = g_object_ref (netns);
}
break;
case PROP_REGISTER_SINGLETON:
/* construct-only */
priv->register_singleton = g_value_get_boolean (value);
......@@ -4147,6 +4197,14 @@ nm_platform_init (NMPlatform *object)
{
}
static void
finalize (GObject *object)
{
NMPlatform *self = NM_PLATFORM (object);
g_clear_object (&self->_netns);
}
static void
nm_platform_class_init (NMPlatformClass *platform_class)
{
......@@ -4156,9 +4214,18 @@ nm_platform_class_init (NMPlatformClass *platform_class)
object_class->set_property = set_property;
object_class->constructed = constructed;
object_class->finalize = finalize;
platform_class->wifi_set_powersave = wifi_set_powersave;
g_object_class_install_property
(object_class, PROP_NETNS_SUPPORT,
g_param_spec_boolean (NM_PLATFORM_NETNS_SUPPORT, "", "",
FALSE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_REGISTER_SINGLETON,
g_param_spec_boolean (NM_PLATFORM_REGISTER_SINGLETON, "", "",
......
......@@ -42,6 +42,7 @@
/******************************************************************/
#define NM_PLATFORM_NETNS_SUPPORT "netns-support"
#define NM_PLATFORM_REGISTER_SINGLETON "register-singleton"
/******************************************************************/
......@@ -462,6 +463,8 @@ typedef struct {
struct _NMPlatform {
GObject parent;
NMPNetns *_netns;
};
typedef struct {
......@@ -669,6 +672,9 @@ _nm_platform_uint8_inv (guint8 scope)
return (guint8) ~scope;
}
NMPNetns *nm_platform_netns_get (NMPlatform *self);
gboolean nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns);
const char *nm_link_type_to_string (NMLinkType link_type);
const char *_nm_platform_error_to_string (NMPlatformError error);
......
This diff is collapsed.
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-platform.c - Handle runtime kernel networking configuration
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2016 Red Hat, Inc.
*/
#ifndef __NMP_NETNS_UTILS_H__
#define __NMP_NETNS_UTILS_H__
/*****************************************************************************/
#define NMP_TYPE_NETNS (nmp_netns_get_type ())
#define NMP_NETNS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMP_TYPE_NETNS, NMPNetns))
#define NMP_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMP_TYPE_NETNS, NMPNetnsClass))
#define NMP_IS_NETNS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMP_TYPE_NETNS))
#define NMP_IS_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMP_TYPE_NETNS))
#define NMP_NETNS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMP_TYPE_NETNS, NMPNetnsClass))
#define NMP_NETNS_FD_NET "fd-net"
#define NMP_NETNS_FD_MNT "fd-mnt"
struct _NMPNetnsPrivate;
struct _NMPNetns {
GObject parent;
struct _NMPNetnsPrivate *priv;
};
typedef struct {
GObjectClass parent;
} NMPNetnsClass;
GType nmp_netns_get_type (void);
NMPNetns *nmp_netns_new (void);
gboolean nmp_netns_push (NMPNetns *self);
gboolean nmp_netns_pop (NMPNetns *self);
NMPNetns *nmp_netns_get_current (void);
NMPNetns *nmp_netns_get_initial (void);
gboolean nmp_netns_is_initial (void);
int nmp_netns_get_fd_net (NMPNetns *self);
int nmp_netns_get_fd_mnt (NMPNetns *self);
static inline void
_nm_auto_pop_netns (NMPNetns **p)
{
if (*p)
nmp_netns_pop (*p);
}
#define nm_auto_pop_netns __attribute__((cleanup(_nm_auto_pop_netns)))
#endif /* __NMP_NETNS_UTILS_H__ */
......@@ -174,10 +174,6 @@ _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev)
* nmp_cache_use_udev_get(). It is on purpose not to test
* for a writable /sys on every call. A minor reason for that is
* performance, but the real reason is reproducibility.
*
* If you want to support changing of whether udev is enabled,
* reset the value via nmp_cache_use_udev_set() carefully -- and
* possibly update the links in the cache accordingly.
* */
initialized = TRUE;
}
......@@ -1191,12 +1187,6 @@ _vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_typ
/******************************************************************/
gboolean
nmp_cache_use_udev_detect ()
{
return access ("/sys", W_OK) == 0;
}
gboolean
nmp_cache_use_udev_get (const NMPCache *cache)
{
......@@ -1205,19 +1195,6 @@ nmp_cache_use_udev_get (const NMPCache *cache)
return cache->use_udev;
}
gboolean
nmp_cache_use_udev_set (NMPCache *cache, gboolean use_udev)
{
g_return_val_if_fail (cache, FALSE);
use_udev = !!use_udev;
if (use_udev == cache->use_udev)
return FALSE;
cache->use_udev = use_udev;
return TRUE;
}
/******************************************************************/
/**
......@@ -1858,7 +1835,7 @@ nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject
/******************************************************************/
NMPCache *
nmp_cache_new ()
nmp_cache_new (gboolean use_udev)
{
NMPCache *cache = g_new (NMPCache, 1);
......@@ -1870,7 +1847,7 @@ nmp_cache_new ()
(NMMultiIndexFuncEqual) nmp_cache_id_equal,
(NMMultiIndexFuncClone) nmp_cache_id_clone,
(NMMultiIndexFuncDestroy) nmp_cache_id_destroy);
cache->use_udev = nmp_cache_use_udev_detect ();
cache->use_udev = !!use_udev;
return cache;
}
......
......@@ -399,9 +399,7 @@ GHashTable *nmp_cache_lookup_all_to_hash (const NMPCache *cache,
gboolean nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *master, const NMPObject *potential_slave, const NMPObject *ignore_slave);
const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int master_ifindex, const NMPObject *potential_slave, const NMPObject *ignore_slave);
gboolean nmp_cache_use_udev_detect (void);
gboolean nmp_cache_use_udev_get (const NMPCache *cache);
gboolean nmp_cache_use_udev_set (NMPCache *cache, gboolean use_udev);
void ASSERT_nmp_cache_is_consistent (const NMPCache *cache);
......@@ -411,7 +409,7 @@ NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPOb
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCache *nmp_cache_new (void);
NMPCache *nmp_cache_new (gboolean use_udev);
void nmp_cache_free (NMPCache *cache);
#endif /* __NMP_OBJECT_H__ */
......@@ -22,6 +22,7 @@
#include <linux/rtnetlink.h>
#include "nm-platform-utils.h"
#include "nm-linux-platform.h"
#include "nm-test-utils.h"
......
......@@ -23,6 +23,8 @@
#include <sched.h>
#include "nmp-object.h"
#include "nmp-netns.h"
#include "nm-platform-utils.h"
#include "test-common.h"
#include "nm-test-utils.h"
......@@ -1846,6 +1848,138 @@ again:
nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0);
}
/******************************************************************/
static void
test_netns_general_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_general_teardown (gpointer fixture, gconstpointer test_data)
{
/* re-create platform instance */
SETUP ();
}
static void
test_netns_general (gpointer fixture, gconstpointer test_data)
{
gs_unref_object NMPlatform *platform_1 = NULL;
gs_unref_object NMPlatform *platform_2 = NULL;
gs_unref_object NMPNetns *netns_2 = NULL;
NMPNetns *netns_tmp;
char sbuf[100];
int i, j, k, errsv;
gboolean ethtool_support;
netns_tmp = nmp_netns_get_current ();
if (!netns_tmp) {
g_test_skip ("No netns support");
return;
}
g_assert (nmp_netns_get_fd_net (netns_tmp) > 0);
if (setns (nmp_netns_get_fd_net (netns_tmp), CLONE_NEWNET) != 0) {
errsv = errno;
_LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (errsv));
g_test_skip ("No netns support (setns failed)");
return;
}
platform_1 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
netns_2 = nmp_netns_new ();
platform_2 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL);
nmp_netns_pop (netns_2);
/* 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");
#define _ADD_DUMMY(platform, name) \
g_assert_cmpint (nm_platform_link_dummy_add ((platform), (name), NULL), ==, NM_PLATFORM_ERROR_SUCCESS)
for (i = 0, j = nmtst_get_rand_int () % 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_int () % 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_int () % 5; i < j; i++)
_ADD_DUMMY (p, nm_sprintf_buf (sbuf, "other-c-%s-%02d", id, i));
#undef _ADD_DUMMY
}
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/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/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/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));
for (i = 0; i < 10; i++) {
NMPlatform *pl;
const char *path;
j = nmtst_get_rand_int () % 2;
if (nmtst_get_rand_int () % 2) {
pl = platform_1;
if (nmtst_get_rand_int () % 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_int () % 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, path, nm_sprintf_buf (sbuf, "%d", j)));
g_assert_cmpstr (nm_platform_sysctl_get (pl, path), ==, nm_sprintf_buf (sbuf, "%d", j));
}
g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6"), ==, NULL);
g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/proc/sys/net/ipv6/conf/dummy2a/disable_ipv6"), ==, NULL);
/* older kernels (Ubuntu 12.04) 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 ("dummy1_", NULL, NULL, NULL));
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy2a", NULL, NULL, NULL));
g_assert (!nmp_utils_ethtool_get_driver_info ("dummy2b", NULL, NULL, NULL));
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));
g_assert (netns_tmp == netns_2);
if (ethtool_support) {
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy1_", NULL, NULL, NULL));
g_assert (!nmp_utils_ethtool_get_driver_info ("dummy2a", NULL, NULL, NULL));
g_assert ( nmp_utils_ethtool_get_driver_info ("dummy2b", NULL, NULL, NULL));
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);
}
/*****************************************************************************/
void
......@@ -1894,5 +2028,7 @@ setup_tests (void)
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_general_setup, test_netns_general, test_netns_general_teardown);
}
}
......@@ -223,9 +223,7 @@ test_cache_link (void)
GUdevDevice *udev_device_3 = g_list_nth_data (global.udev_devices, 0);
NMPCacheOpsType ops_type;
cache = nmp_cache_new ();
nmp_cache_use_udev_set (cache, g_rand_int_range (nmtst_get_rand (), 0, 2));
cache = nmp_cache_new (nmtst_get_rand_int () % 2);
/* if we have a link, and don't set is_in_netlink, adding it has no effect. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
......
......@@ -139,6 +139,14 @@ if [ $RESULT -ne 0 -a $RESULT -ne 77 ]; then
exit $RESULT
fi
if [ $HAS_ERRORS -eq 0 ]; then
# valgrind doesn't support setns syscall and spams the logfile.
# hack around it...
if [ "$(basename "$TEST")" = 'test-link-linux' -a -z "$(sed -e '/^--[0-9]\+-- WARNING: unhandled .* syscall: /,/^--[0-9]\+-- it at http.*\.$/d' "$LOGFILE")" ]; then
HAS_ERRORS=1
fi
fi
if [ $HAS_ERRORS -eq 0 ]; then
# shouldn't actually happen...
echo "valgrind succeeded, but log is not empty: '`realpath "$LOGFILE"`'" >&2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment