summaryrefslogtreecommitdiff
path: root/src/platform/nm-linux-platform.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-02-19 01:06:28 +0100
committerThomas Haller <thaller@redhat.com>2016-03-06 16:41:31 +0100
commit04a0c0bfa6c1a0bbef4602b66cf72bbc3dfaeeac (patch)
tree3390cd28e8c5d96620024da4014b8363b2a2a4de /src/platform/nm-linux-platform.c
parent0e356ed511408372f29c4190cb9285b5ea192ef2 (diff)
downloadNetworkManager-th/platform-netns-bgo762408.tar.gz
platform: add network namespace support to platformth/platform-netns-bgo762408
Add a new NMPNetns class. This allows creation, deletion and switching of network namespaces. The API only offers push/pop operations to switch the namespace. This way the API enforces to always restore the previous namespace that was set before. A NMPlatform instance not only uses the netlink socket, but also sysfs, udev, ethtool, mii. Still, a NMPlatform instance lives entirely inside one namespace. It is not spanning multiple namespaces. To properly support network namespaces, the platform instance must switch the namespace as necessary, transparent to the caller. In case of udev, it is only supported on the main namespace. For now, network namespaces are not actually used and are disabled via NM_PLATFORM_NETNS_SUPPORT argument. https://bugzilla.gnome.org/show_bug.cgi?id=762408
Diffstat (limited to 'src/platform/nm-linux-platform.c')
-rw-r--r--src/platform/nm-linux-platform.c162
1 files changed, 101 insertions, 61 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 2bdcb9bcd8..a089edef09 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -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,6 +2414,7 @@ void
nm_linux_platform_setup (void)
{
g_object_new (NM_TYPE_LINUX_PLATFORM,
+ NM_PLATFORM_NETNS_SUPPORT, FALSE,
NM_PLATFORM_REGISTER_SINGLETON, TRUE,
NULL);
}
@@ -2417,6 +2422,16 @@ nm_linux_platform_setup (void)
/******************************************************************/
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)
{
GError *error = NULL;
@@ -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"));
@@ -5939,7 +5968,8 @@ nm_linux_platform_init (NMLinuxPlatform *self)
NMLinuxPlatformPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate);
gboolean use_udev;
- use_udev = access ("/sys", W_OK) == 0;
+ use_udev = nmp_netns_is_initial ()
+ && access ("/sys", W_OK) == 0;
self->priv = priv;
@@ -5963,7 +5993,17 @@ constructed (GObject *_object)
gboolean status;
int nle;
- _LOGD ("create (%s udev)",
+ 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 ();