diff options
author | Thomas Haller <thaller@redhat.com> | 2016-02-19 01:06:28 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-03-06 16:41:31 +0100 |
commit | 04a0c0bfa6c1a0bbef4602b66cf72bbc3dfaeeac (patch) | |
tree | 3390cd28e8c5d96620024da4014b8363b2a2a4de /src/platform/nm-linux-platform.c | |
parent | 0e356ed511408372f29c4190cb9285b5ea192ef2 (diff) | |
download | NetworkManager-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.c | 162 |
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 (); |