mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-03-27 09:20:42 +01:00
platform: merge branch 'th/platform-netns-bgo762408'
https://bugzilla.gnome.org/show_bug.cgi?id=762408
This commit is contained in:
commit
b2b73809c5
13 changed files with 919 additions and 113 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
|
||||
#include "nm-core-utils.h"
|
||||
#include "nmp-object.h"
|
||||
#include "nmp-netns.h"
|
||||
#include "nm-platform-utils.h"
|
||||
#include "wifi/wifi-utils.h"
|
||||
#include "wifi/wifi-utils-wext.h"
|
||||
|
|
@ -221,6 +222,7 @@ static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActi
|
|||
static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
|
||||
static void cache_prune_candidates_prune (NMPlatform *platform);
|
||||
static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
|
||||
static void _assert_netns_current (NMPlatform *platform);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -647,6 +649,8 @@ _linktype_get_type (NMPlatform *platform,
|
|||
{
|
||||
guint i;
|
||||
|
||||
_assert_netns_current (platform);
|
||||
|
||||
if (completed_from_cache) {
|
||||
const NMPObject *obj;
|
||||
|
||||
|
|
@ -2410,12 +2414,23 @@ void
|
|||
nm_linux_platform_setup (void)
|
||||
{
|
||||
g_object_new (NM_TYPE_LINUX_PLATFORM,
|
||||
NM_PLATFORM_NETNS_SUPPORT, FALSE,
|
||||
NM_PLATFORM_REGISTER_SINGLETON, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
_assert_netns_current (NMPlatform *platform)
|
||||
{
|
||||
#if NM_MORE_ASSERTS
|
||||
nm_assert (NM_IS_LINUX_PLATFORM (platform));
|
||||
|
||||
nm_assert (NM_IN_SET (nm_platform_netns_get (platform), NULL, nmp_netns_get_current ()));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
_log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *value)
|
||||
{
|
||||
|
|
@ -2449,6 +2464,7 @@ _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *va
|
|||
static gboolean
|
||||
sysctl_set (NMPlatform *platform, const char *path, const char *value)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
int fd, tries;
|
||||
gssize nwrote;
|
||||
gsize len;
|
||||
|
|
@ -2464,6 +2480,9 @@ sysctl_set (NMPlatform *platform, const char *path, const char *value)
|
|||
/* Don't write to suspicious locations */
|
||||
g_assert (!strstr (path, "/../"));
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
fd = open (path, O_WRONLY | O_TRUNC);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
|
|
@ -2578,6 +2597,7 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *co
|
|||
static char *
|
||||
sysctl_get (NMPlatform *platform, const char *path)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
GError *error = NULL;
|
||||
char *contents;
|
||||
|
||||
|
|
@ -2587,6 +2607,9 @@ sysctl_get (NMPlatform *platform, const char *path)
|
|||
/* Don't write to suspicious locations */
|
||||
g_assert (!strstr (path, "/../"));
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return NULL;
|
||||
|
||||
if (!g_file_get_contents (path, &contents, NULL, &error)) {
|
||||
/* We assume FAILED means EOPNOTSUP */
|
||||
if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
|
||||
|
|
@ -2651,6 +2674,9 @@ do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cach
|
|||
nm_assert (!obj || cache_op == NMP_CACHE_OPS_REMOVED || obj == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
|
||||
nm_assert (!obj || cache_op != NMP_CACHE_OPS_REMOVED || obj != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
|
||||
|
||||
/* we raise the signals inside the namespace of the NMPlatform instance. */
|
||||
_assert_netns_current (platform);
|
||||
|
||||
switch (cache_op) {
|
||||
case NMP_CACHE_OPS_ADDED:
|
||||
if (!nmp_object_is_visible (obj))
|
||||
|
|
@ -4135,11 +4161,15 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable
|
|||
static gboolean
|
||||
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
const char *name = nm_platform_link_get_name (platform, ifindex);
|
||||
|
||||
if (!name)
|
||||
return FALSE;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
/* We use netlink for the actual carrier detection, but netlink can't tell
|
||||
* us whether the device actually supports carrier detection in the first
|
||||
* place. We assume any device that does implements one of these two APIs.
|
||||
|
|
@ -4150,6 +4180,7 @@ link_supports_carrier_detect (NMPlatform *platform, int ifindex)
|
|||
static gboolean
|
||||
link_supports_vlans (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
const NMPObject *obj;
|
||||
|
||||
obj = cache_lookup_link (platform, ifindex);
|
||||
|
|
@ -4158,6 +4189,9 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
|
|||
if (!obj || obj->link.arptype != ARPHRD_ETHER)
|
||||
return FALSE;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
return nmp_utils_ethtool_supports_vlans (obj->link.name);
|
||||
}
|
||||
|
||||
|
|
@ -4196,6 +4230,11 @@ link_get_permanent_address (NMPlatform *platform,
|
|||
guint8 *buf,
|
||||
size_t *length)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
return nmp_utils_ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length);
|
||||
}
|
||||
|
||||
|
|
@ -4975,15 +5014,19 @@ wifi_get_wifi_data (NMPlatform *platform, int ifindex)
|
|||
|
||||
return wifi_data;
|
||||
}
|
||||
#define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL; \
|
||||
WifiData *wifi_data; \
|
||||
if (!nm_platform_netns_push (platform, &netns)) \
|
||||
return retval; \
|
||||
wifi_data = wifi_get_wifi_data (platform, ifindex); \
|
||||
if (!wifi_data) \
|
||||
return retval;
|
||||
|
||||
static gboolean
|
||||
wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
|
||||
if (caps)
|
||||
*caps = wifi_utils_get_caps (wifi_data);
|
||||
return TRUE;
|
||||
|
|
@ -4992,90 +5035,64 @@ wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabiliti
|
|||
static gboolean
|
||||
wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
|
||||
return wifi_utils_get_bssid (wifi_data, bssid);
|
||||
}
|
||||
|
||||
static guint32
|
||||
wifi_get_frequency (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return 0;
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
|
||||
return wifi_utils_get_freq (wifi_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wifi_get_quality (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
|
||||
return wifi_utils_get_qual (wifi_data);
|
||||
}
|
||||
|
||||
static guint32
|
||||
wifi_get_rate (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
|
||||
return wifi_utils_get_rate (wifi_data);
|
||||
}
|
||||
|
||||
static NM80211Mode
|
||||
wifi_get_mode (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return NM_802_11_MODE_UNKNOWN;
|
||||
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, NM_802_11_MODE_UNKNOWN);
|
||||
return wifi_utils_get_mode (wifi_data);
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (wifi_data)
|
||||
wifi_utils_set_mode (wifi_data, mode);
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
|
||||
wifi_utils_set_mode (wifi_data, mode);
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_set_powersave (NMPlatform *platform, int ifindex, guint32 powersave)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (wifi_data)
|
||||
wifi_utils_set_powersave (wifi_data, powersave);
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
|
||||
wifi_utils_set_powersave (wifi_data, powersave);
|
||||
}
|
||||
|
||||
static guint32
|
||||
wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return 0;
|
||||
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
|
||||
return wifi_utils_find_freq (wifi_data, freqs);
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (wifi_data)
|
||||
wifi_utils_indicate_addressing_running (wifi_data, running);
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
|
||||
wifi_utils_indicate_addressing_running (wifi_data, running);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
|
@ -5083,33 +5100,21 @@ wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean ru
|
|||
static guint32
|
||||
mesh_get_channel (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return 0;
|
||||
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
|
||||
return wifi_utils_get_mesh_channel (wifi_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
|
||||
return wifi_utils_set_mesh_channel (wifi_data, channel);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
|
||||
{
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
|
||||
WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
|
||||
return wifi_utils_set_mesh_ssid (wifi_data, ssid, len);
|
||||
}
|
||||
|
||||
|
|
@ -5118,8 +5123,12 @@ mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
|
|||
static gboolean
|
||||
link_get_wake_on_lan (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
NMLinkType type = nm_platform_link_get_type (platform, ifindex);
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
if (type == NM_LINK_TYPE_ETHERNET)
|
||||
return nmp_utils_ethtool_get_wake_on_lan (nm_platform_link_get_name (platform, ifindex));
|
||||
else if (type == NM_LINK_TYPE_WIFI) {
|
||||
|
|
@ -5140,6 +5149,11 @@ link_get_driver_info (NMPlatform *platform,
|
|||
char **out_driver_version,
|
||||
char **out_fw_version)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
return nmp_utils_ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex),
|
||||
out_driver_name,
|
||||
out_driver_version,
|
||||
|
|
@ -5721,6 +5735,7 @@ out:
|
|||
static gboolean
|
||||
event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
int r, nle;
|
||||
struct pollfd pfd;
|
||||
|
|
@ -5733,6 +5748,9 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
|
|||
gint64 timeout_abs_ns;
|
||||
} data_next;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return FALSE;
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
while (TRUE) {
|
||||
|
|
@ -5837,7 +5855,14 @@ cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_dev
|
|||
NMPCacheOpsType cache_op;
|
||||
|
||||
cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udev_device, &obj_cache, &was_visible, cache_pre_hook, platform);
|
||||
do_emit_signal (platform, obj_cache, cache_op, was_visible);
|
||||
|
||||
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return;
|
||||
do_emit_signal (platform, obj_cache, cache_op, was_visible);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -5908,6 +5933,7 @@ handle_udev_event (GUdevClient *client,
|
|||
GUdevDevice *udev_device,
|
||||
gpointer user_data)
|
||||
{
|
||||
nm_auto_pop_netns NMPNetns *netns = NULL;
|
||||
NMPlatform *platform = NM_PLATFORM (user_data);
|
||||
const char *subsys;
|
||||
const char *ifindex;
|
||||
|
|
@ -5915,6 +5941,9 @@ handle_udev_event (GUdevClient *client,
|
|||
|
||||
g_return_if_fail (action != NULL);
|
||||
|
||||
if (!nm_platform_netns_push (platform, &netns))
|
||||
return;
|
||||
|
||||
/* A bit paranoid */
|
||||
subsys = g_udev_device_get_subsystem (udev_device);
|
||||
g_return_if_fail (!g_strcmp0 (subsys, "net"));
|
||||
|
|
@ -5937,15 +5966,22 @@ static void
|
|||
nm_linux_platform_init (NMLinuxPlatform *self)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate);
|
||||
gboolean use_udev;
|
||||
|
||||
use_udev = nmp_netns_is_initial ()
|
||||
&& access ("/sys", W_OK) == 0;
|
||||
|
||||
self->priv = priv;
|
||||
|
||||
priv->nlh_seq_next = 1;
|
||||
priv->cache = nmp_cache_new ();
|
||||
priv->cache = nmp_cache_new (use_udev);
|
||||
priv->delayed_action.list_master_connected = g_ptr_array_new ();
|
||||
priv->delayed_action.list_refresh_link = g_ptr_array_new ();
|
||||
priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
|
||||
priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
|
||||
|
||||
if (use_udev)
|
||||
priv->udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -5953,14 +5989,22 @@ constructed (GObject *_object)
|
|||
{
|
||||
NMPlatform *platform = NM_PLATFORM (_object);
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
const char *udev_subsys[] = { "net", NULL };
|
||||
int channel_flags;
|
||||
gboolean status;
|
||||
int nle;
|
||||
GUdevEnumerator *enumerator;
|
||||
GList *devices, *iter;
|
||||
|
||||
_LOGD ("create");
|
||||
nm_assert (!platform->_netns || platform->_netns == nmp_netns_get_current ());
|
||||
|
||||
_LOGD ("create (%s netns, %s, %s udev)",
|
||||
!platform->_netns ? "ignore" : "use",
|
||||
!platform->_netns && nmp_netns_is_initial ()
|
||||
? "initial netns"
|
||||
: (!nmp_netns_get_current ()
|
||||
? "no netns support"
|
||||
: nm_sprintf_bufa (100, "in netns[%p]%s",
|
||||
nmp_netns_get_current (),
|
||||
nmp_netns_get_current () == nmp_netns_get_initial () ? "/main" : "")),
|
||||
nmp_cache_use_udev_get (priv->cache) ? "use" : "no");
|
||||
|
||||
priv->nlh = nl_socket_alloc ();
|
||||
g_assert (priv->nlh);
|
||||
|
|
@ -5992,16 +6036,12 @@ constructed (GObject *_object)
|
|||
|
||||
channel_flags = g_io_channel_get_flags (priv->event_channel);
|
||||
status = g_io_channel_set_flags (priv->event_channel,
|
||||
channel_flags | G_IO_FLAG_NONBLOCK, NULL);
|
||||
channel_flags | G_IO_FLAG_NONBLOCK, NULL);
|
||||
g_assert (status);
|
||||
priv->event_id = g_io_add_watch (priv->event_channel,
|
||||
(EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
|
||||
event_handler, platform);
|
||||
|
||||
/* Set up udev monitoring */
|
||||
priv->udev_client = g_udev_client_new (udev_subsys);
|
||||
g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
|
||||
|
||||
/* complete construction of the GObject instance before populating the cache. */
|
||||
G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
|
||||
|
||||
|
|
@ -6016,19 +6056,27 @@ constructed (GObject *_object)
|
|||
|
||||
delayed_action_handle_all (platform, FALSE);
|
||||
|
||||
/* And read initial device list */
|
||||
enumerator = g_udev_enumerator_new (priv->udev_client);
|
||||
g_udev_enumerator_add_match_subsystem (enumerator, "net");
|
||||
/* Set up udev monitoring */
|
||||
if (priv->udev_client) {
|
||||
GUdevEnumerator *enumerator;
|
||||
GList *devices, *iter;
|
||||
|
||||
g_udev_enumerator_add_match_is_initialized (enumerator);
|
||||
g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
|
||||
|
||||
devices = g_udev_enumerator_execute (enumerator);
|
||||
for (iter = devices; iter; iter = g_list_next (iter)) {
|
||||
udev_device_added (platform, G_UDEV_DEVICE (iter->data));
|
||||
g_object_unref (G_UDEV_DEVICE (iter->data));
|
||||
/* And read initial device list */
|
||||
enumerator = g_udev_enumerator_new (priv->udev_client);
|
||||
g_udev_enumerator_add_match_subsystem (enumerator, "net");
|
||||
|
||||
g_udev_enumerator_add_match_is_initialized (enumerator);
|
||||
|
||||
devices = g_udev_enumerator_execute (enumerator);
|
||||
for (iter = devices; iter; iter = g_list_next (iter)) {
|
||||
udev_device_added (platform, G_UDEV_DEVICE (iter->data));
|
||||
g_object_unref (G_UDEV_DEVICE (iter->data));
|
||||
}
|
||||
g_list_free (devices);
|
||||
g_object_unref (enumerator);
|
||||
}
|
||||
g_list_free (devices);
|
||||
g_object_unref (enumerator);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -6047,6 +6095,11 @@ dispose (GObject *object)
|
|||
|
||||
g_clear_pointer (&priv->prune_candidates, g_hash_table_unref);
|
||||
|
||||
if (priv->udev_client) {
|
||||
g_signal_handlers_disconnect_by_func (priv->udev_client, G_CALLBACK (handle_udev_event), platform);
|
||||
g_clear_object (&priv->udev_client);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
|
@ -6066,7 +6119,6 @@ nm_linux_platform_finalize (GObject *object)
|
|||
g_io_channel_unref (priv->event_channel);
|
||||
nl_socket_free (priv->nlh);
|
||||
|
||||
g_object_unref (priv->udev_client);
|
||||
g_hash_table_unref (priv->wifi_data);
|
||||
|
||||
if (priv->sysctl_get_prev_values) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
489
src/platform/nmp-netns.c
Normal file
489
src/platform/nmp-netns.c
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
/* -*- 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.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
#include "nmp-netns.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
#define _NMLOG_DOMAIN LOGD_PLATFORM
|
||||
#define _NMLOG_PREFIX_NAME "netns"
|
||||
#define _NMLOG(level, netns, ...) \
|
||||
G_STMT_START { \
|
||||
NMLogLevel _level = (level); \
|
||||
\
|
||||
if (nm_logging_enabled (_level, _NMLOG_DOMAIN)) { \
|
||||
NMPNetns *_netns = (netns); \
|
||||
char _sbuf[20]; \
|
||||
\
|
||||
_nm_log (_level, _NMLOG_DOMAIN, 0, \
|
||||
"%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
_NMLOG_PREFIX_NAME, \
|
||||
(_netns ? nm_sprintf_buf (_sbuf, "[%p]", _netns) : "") \
|
||||
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
|
||||
PROP_FD_NET,
|
||||
PROP_FD_MNT,
|
||||
);
|
||||
|
||||
typedef struct _NMPNetnsPrivate NMPNetnsPrivate;
|
||||
|
||||
struct _NMPNetnsPrivate {
|
||||
int fd_net;
|
||||
int fd_mnt;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
NMPNetns *netns;
|
||||
int count;
|
||||
} NetnsInfo;
|
||||
|
||||
static void _stack_push (NMPNetns *netns);
|
||||
static NMPNetns *_netns_new (GError **error);
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
static GArray *netns_stack = NULL;
|
||||
|
||||
static void
|
||||
_stack_ensure_init_impl (void)
|
||||
{
|
||||
NMPNetns *netns;
|
||||
GError *error = NULL;
|
||||
|
||||
nm_assert (!netns_stack);
|
||||
|
||||
netns_stack = g_array_new (FALSE, FALSE, sizeof (NetnsInfo));
|
||||
|
||||
/* at the bottom of the stack we must try to create a netns instance
|
||||
* that we never pop. It's the base to which we need to return. */
|
||||
|
||||
netns = _netns_new (&error);
|
||||
|
||||
if (!netns) {
|
||||
/* don't know how to recover from this error. Netns are not supported. */
|
||||
_LOGE (NULL, "failed to create initial netns: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
_stack_push (netns);
|
||||
|
||||
/* we leak this instance inside netns_stack. It cannot be popped. */
|
||||
g_object_unref (netns);
|
||||
}
|
||||
#define _stack_ensure_init() \
|
||||
G_STMT_START { \
|
||||
if (G_UNLIKELY (!netns_stack)) { \
|
||||
_stack_ensure_init_impl (); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
static NetnsInfo *
|
||||
_stack_peek (void)
|
||||
{
|
||||
nm_assert (netns_stack);
|
||||
|
||||
if (netns_stack->len > 0)
|
||||
return &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1));
|
||||
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 *
|
||||
_stack_bottom (void)
|
||||
{
|
||||
nm_assert (netns_stack);
|
||||
|
||||
if (netns_stack->len > 0)
|
||||
return &g_array_index (netns_stack, NetnsInfo, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_stack_push (NMPNetns *netns)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
|
||||
nm_assert (netns_stack);
|
||||
nm_assert (NMP_IS_NETNS (netns));
|
||||
|
||||
g_array_set_size (netns_stack, netns_stack->len + 1);
|
||||
|
||||
info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1));
|
||||
info->netns = g_object_ref (netns);
|
||||
info->count = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_stack_pop (void)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
|
||||
nm_assert (netns_stack);
|
||||
nm_assert (netns_stack->len > 1);
|
||||
|
||||
info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1));
|
||||
|
||||
nm_assert (NMP_IS_NETNS (info->netns));
|
||||
nm_assert (info->count == 1);
|
||||
|
||||
g_object_unref (info->netns);
|
||||
|
||||
g_array_set_size (netns_stack, netns_stack->len - 1);
|
||||
}
|
||||
|
||||
static guint
|
||||
_stack_size (void)
|
||||
{
|
||||
nm_assert (netns_stack);
|
||||
|
||||
return netns_stack->len;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
G_DEFINE_TYPE (NMPNetns, nmp_netns, G_TYPE_OBJECT);
|
||||
|
||||
#define NMP_NETNS_GET_PRIVATE(o) ((o)->priv)
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
static NMPNetns *
|
||||
_netns_new (GError **error)
|
||||
{
|
||||
NMPNetns *self;
|
||||
int fd_net, fd_mnt;
|
||||
int errsv;
|
||||
|
||||
fd_net = open ("/proc/self/ns/net", O_RDONLY);
|
||||
if (fd_net == -1) {
|
||||
errsv = errno;
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
|
||||
"Failed opening netns: %s",
|
||||
g_strerror (errsv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd_mnt = open ("/proc/self/ns/mnt", O_RDONLY);
|
||||
if (fd_mnt == -1) {
|
||||
errsv = errno;
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
|
||||
"Failed opening mntns: %s",
|
||||
g_strerror (errsv));
|
||||
close (fd_net);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = g_object_new (NMP_TYPE_NETNS,
|
||||
NMP_NETNS_FD_NET, fd_net,
|
||||
NMP_NETNS_FD_MNT, fd_mnt,
|
||||
NULL);
|
||||
|
||||
_LOGD (self, "new netns (net:%d, mnt:%d)", fd_net, fd_mnt);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_netns_switch (NMPNetns *self, NMPNetns *netns_fail)
|
||||
{
|
||||
int errsv;
|
||||
|
||||
if (setns (self->priv->fd_net, CLONE_NEWNET) != 0) {
|
||||
errsv = errno;
|
||||
_LOGE (self, "failed to switch netns: %s", g_strerror (errsv));
|
||||
return FALSE;
|
||||
}
|
||||
if (setns (self->priv->fd_mnt, CLONE_NEWNS) != 0) {
|
||||
errsv = errno;
|
||||
_LOGE (self, "failed to switch mntns: %s", g_strerror (errsv));
|
||||
|
||||
/* try to fix the mess by returning to the previous netns. */
|
||||
if (netns_fail) {
|
||||
if (setns (netns_fail->priv->fd_net, CLONE_NEWNET) != 0) {
|
||||
errsv = errno;
|
||||
_LOGE (netns_fail, "failed to restore netns: %s", g_strerror (errsv));
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
int
|
||||
nmp_netns_get_fd_net (NMPNetns *self)
|
||||
{
|
||||
g_return_val_if_fail (NMP_IS_NETNS (self), 0);
|
||||
|
||||
return self->priv->fd_net;
|
||||
}
|
||||
|
||||
int
|
||||
nmp_netns_get_fd_mnt (NMPNetns *self)
|
||||
{
|
||||
g_return_val_if_fail (NMP_IS_NETNS (self), 0);
|
||||
|
||||
return self->priv->fd_mnt;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
gboolean
|
||||
nmp_netns_push (NMPNetns *self)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
|
||||
g_return_val_if_fail (NMP_IS_NETNS (self), FALSE);
|
||||
|
||||
_stack_ensure_init ();
|
||||
|
||||
info = _stack_peek ();
|
||||
g_return_val_if_fail (info, FALSE);
|
||||
|
||||
if (info->netns == self) {
|
||||
info->count++;
|
||||
_LOGt (self, "push (increase count to %d)", info->count);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_LOGD (self, "push (was %p)", info->netns);
|
||||
|
||||
if (!_netns_switch (self, info->netns))
|
||||
return FALSE;
|
||||
|
||||
_stack_push (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NMPNetns *
|
||||
nmp_netns_new (void)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
NMPNetns *self;
|
||||
int errsv;
|
||||
GError *error = NULL;
|
||||
|
||||
_stack_ensure_init ();
|
||||
|
||||
if (!_stack_peek ()) {
|
||||
/* there are no netns instances. We cannot create a new one
|
||||
* (because after unshare we couldn't return to the original one). */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) {
|
||||
errsv = errno;
|
||||
_LOGE (NULL, "failed to create new net and mnt namespace: %s", g_strerror (errsv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mount ("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
|
||||
_LOGE (NULL, "failed mount --make-rslave: %s", error->message);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (umount2 ("/sys", MNT_DETACH) < 0) {
|
||||
_LOGE (NULL, "failed umount /sys: %s", error->message);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (mount ("sysfs", "/sys", "sysfs", 0, NULL) < 0) {
|
||||
_LOGE (NULL, "failed mount /sys: %s", error->message);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
self = _netns_new (&error);
|
||||
if (!self) {
|
||||
_LOGE (NULL, "failed to create netns after unshare: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
_stack_push (self);
|
||||
|
||||
return self;
|
||||
err_out:
|
||||
info = _stack_peek ();
|
||||
_netns_switch (info->netns, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmp_netns_pop (NMPNetns *self)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
|
||||
g_return_val_if_fail (NMP_IS_NETNS (self), FALSE);
|
||||
|
||||
_stack_ensure_init ();
|
||||
|
||||
info = _stack_peek ();
|
||||
|
||||
g_return_val_if_fail (info, FALSE);
|
||||
g_return_val_if_fail (info->netns == self, FALSE);
|
||||
|
||||
if (info->count > 1) {
|
||||
info->count--;
|
||||
_LOGt (self, "pop (decrease count to %d)", info->count);
|
||||
return TRUE;
|
||||
}
|
||||
g_return_val_if_fail (info->count == 1, FALSE);
|
||||
|
||||
/* cannot pop the original netns. */
|
||||
g_return_val_if_fail (_stack_size () > 1, FALSE);
|
||||
|
||||
_LOGD (self, "pop (restore %p)", _stack_peek2 ());
|
||||
|
||||
_stack_pop ();
|
||||
info = _stack_peek ();
|
||||
|
||||
nm_assert (info);
|
||||
|
||||
return _netns_switch (info->netns, NULL);
|
||||
}
|
||||
|
||||
NMPNetns *
|
||||
nmp_netns_get_current (void)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
|
||||
_stack_ensure_init ();
|
||||
|
||||
info = _stack_peek ();
|
||||
return info ? info->netns : NULL;
|
||||
}
|
||||
|
||||
NMPNetns *
|
||||
nmp_netns_get_initial (void)
|
||||
{
|
||||
NetnsInfo *info;
|
||||
|
||||
_stack_ensure_init ();
|
||||
|
||||
info = _stack_bottom ();
|
||||
return info ? info->netns : NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmp_netns_is_initial (void)
|
||||
{
|
||||
if (G_UNLIKELY (!netns_stack))
|
||||
return TRUE;
|
||||
|
||||
return nmp_netns_get_current () == nmp_netns_get_initial ();
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
static void
|
||||
set_property (GObject *object, guint prop_id,
|
||||
const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
NMPNetns *self = NMP_NETNS (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_FD_NET:
|
||||
/* construct only */
|
||||
self->priv->fd_net = g_value_get_int (value);
|
||||
g_return_if_fail (self->priv->fd_net > 0);
|
||||
break;
|
||||
case PROP_FD_MNT:
|
||||
/* construct only */
|
||||
self->priv->fd_mnt = g_value_get_int (value);
|
||||
g_return_if_fail (self->priv->fd_mnt > 0);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nmp_netns_init (NMPNetns *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NMP_TYPE_NETNS, NMPNetnsPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMPNetns *self = NMP_NETNS (object);
|
||||
|
||||
if (self->priv->fd_net > 0) {
|
||||
close (self->priv->fd_net);
|
||||
self->priv->fd_net = 0;
|
||||
}
|
||||
|
||||
if (self->priv->fd_mnt > 0) {
|
||||
close (self->priv->fd_mnt);
|
||||
self->priv->fd_mnt = 0;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (nmp_netns_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nmp_netns_class_init (NMPNetnsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (NMPNetnsPrivate));
|
||||
|
||||
object_class->set_property = set_property;
|
||||
object_class->dispose = dispose;
|
||||
|
||||
obj_properties[PROP_FD_NET]
|
||||
= g_param_spec_int (NMP_NETNS_FD_NET, "", "",
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
obj_properties[PROP_FD_MNT]
|
||||
= g_param_spec_int (NMP_NETNS_FD_MNT, "", "",
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
||||
}
|
||||
70
src/platform/nmp-netns.h
Normal file
70
src/platform/nmp-netns.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- 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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue