diff options
| author | Michael Biebl <biebl@debian.org> | 2016-03-30 00:56:30 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2016-03-30 00:56:30 +0200 |
| commit | d9c99a29a0d3384c9c3d2adce430f5cb1134ab6a (patch) | |
| tree | fa41baf72753961e71dd8d5bdbe2b89c9109e4f1 /src/platform | |
| parent | c2de0d98ba39e0a1a970d066fd19be786092f376 (diff) | |
Imported Upstream version 1.1.92 upstream/1.1.92
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/nm-fake-platform.c | 2 | ||||
| -rw-r--r-- | src/platform/nm-linux-platform.c | 282 | ||||
| -rw-r--r-- | src/platform/nm-platform-utils.c | 106 | ||||
| -rw-r--r-- | src/platform/nm-platform-utils.h | 15 | ||||
| -rw-r--r-- | src/platform/nm-platform.c | 199 | ||||
| -rw-r--r-- | src/platform/nm-platform.h | 25 | ||||
| -rw-r--r-- | src/platform/nmp-netns.c | 732 | ||||
| -rw-r--r-- | src/platform/nmp-netns.h | 74 | ||||
| -rw-r--r-- | src/platform/nmp-object.c | 27 | ||||
| -rw-r--r-- | src/platform/nmp-object.h | 4 | ||||
| -rw-r--r-- | src/platform/tests/test-address.c | 14 | ||||
| -rw-r--r-- | src/platform/tests/test-cleanup.c | 2 | ||||
| -rw-r--r-- | src/platform/tests/test-common.c | 122 | ||||
| -rw-r--r-- | src/platform/tests/test-common.h | 19 | ||||
| -rw-r--r-- | src/platform/tests/test-general.c | 4 | ||||
| -rw-r--r-- | src/platform/tests/test-link.c | 501 | ||||
| -rw-r--r-- | src/platform/tests/test-nmp-object.c | 4 | ||||
| -rw-r--r-- | src/platform/tests/test-route.c | 4 | ||||
| -rw-r--r-- | src/platform/wifi/wifi-utils-wext.c | 25 |
19 files changed, 1760 insertions, 401 deletions
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 68b72b19..fdb11eac 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -890,6 +890,7 @@ ip4_address_add (NMPlatform *platform, in_addr_t peer_addr, guint32 lifetime, guint32 preferred, + guint32 flags, const char *label) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); @@ -905,6 +906,7 @@ ip4_address_add (NMPlatform *platform, address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = lifetime; address.preferred = preferred; + address.n_ifa_flags = flags; if (label) g_strlcpy (address.label, label, sizeof (address.label)); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 196e75cb..e2ff1f61 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; @@ -1673,11 +1677,9 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) obj->ip_address.source = NM_IP_CONFIG_SOURCE_KERNEL; - if (!is_v4) { - obj->ip6_address.n_ifa_flags = tb[IFA_FLAGS] - ? nla_get_u32 (tb[IFA_FLAGS]) - : ifa->ifa_flags; - } + obj->ip_address.n_ifa_flags = tb[IFA_FLAGS] + ? nla_get_u32 (tb[IFA_FLAGS]) + : ifa->ifa_flags; if (is_v4) { if (tb[IFA_LABEL]) { @@ -2225,7 +2227,7 @@ _nl_msg_new_address (int nlmsg_type, NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca); } - if (flags & ~0xFF) { + if (flags & ~((guint32) 0xFF)) { /* only set the IFA_FLAGS attribute, if they actually contain additional * flags that are not already set to am.ifa_flags. * @@ -2412,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); } @@ -2419,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; @@ -2451,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; @@ -2466,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) { @@ -2580,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; @@ -2589,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) @@ -2653,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)) @@ -3857,6 +3881,7 @@ do_change_link (NMPlatform *platform, int ifindex, struct nl_msg *nlmsg) { + nm_auto_pop_netns NMPNetns *netns = NULL; WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; int nle; char s_buf[256]; @@ -3864,6 +3889,9 @@ do_change_link (NMPlatform *platform, NMLogLevel log_level = LOGL_DEBUG; const char *log_result = "failure", *log_detail = ""; + if (!nm_platform_netns_push (platform, &netns)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + retry: nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result); if (nle < 0) { @@ -3927,7 +3955,7 @@ link_add (NMPlatform *platform, * bond0 automatically. */ if (!g_file_test ("/sys/class/net/bonding_masters", G_FILE_TEST_EXISTS)) - nm_utils_modprobe (NULL, TRUE, "bonding", "max_bonds=0", NULL); + (void) nm_utils_modprobe (NULL, TRUE, "bonding", "max_bonds=0", NULL); } _LOGD ("link: add link '%s' of type '%s' (%d)", @@ -3994,7 +4022,7 @@ link_get_type_name (NMPlatform *platform, int ifindex) return nm_link_type_to_string (obj->link.type); } /* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */ - return str_if_set (obj->link.kind, "unknown"); + return obj->link.kind ?: "unknown"; } static gboolean @@ -4023,6 +4051,31 @@ link_refresh (NMPlatform *platform, int ifindex) return !!cache_lookup_link (platform, ifindex); } +static gboolean +link_set_netns (NMPlatform *platform, + int ifindex, + int netns_fd) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + _LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if (!nlmsg) + return FALSE; + + NLA_PUT (nlmsg, IFLA_NET_NS_FD, 4, &netns_fd); + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; + +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static NMPlatformError link_change_flags (NMPlatform *platform, int ifindex, @@ -4137,11 +4190,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. @@ -4152,6 +4209,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); @@ -4160,6 +4218,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); } @@ -4198,6 +4259,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); } @@ -4234,7 +4300,7 @@ link_get_physical_port_id (NMPlatform *platform, int ifindex) if (!ifname) return NULL; - ifname = ASSERT_VALID_PATH_COMPONENT (ifname); + ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname); path = g_strdup_printf ("/sys/class/net/%s/phys_port_id", ifname); id = sysctl_get (platform, path); @@ -4254,7 +4320,7 @@ link_get_dev_id (NMPlatform *platform, int ifindex) if (!ifname) return 0; - ifname = ASSERT_VALID_PATH_COMPONENT (ifname); + ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname); path = g_strdup_printf ("/sys/class/net/%s/dev_id", ifname); id = sysctl_get (platform, path); @@ -4837,7 +4903,7 @@ tun_add (NMPlatform *platform, const char *name, gboolean tap, if (fd < 0) return FALSE; - strncpy (ifr.ifr_name, name, IFNAMSIZ); + nm_utils_ifname_cpy (ifr.ifr_name, name); ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN; if (!pi) @@ -4930,7 +4996,7 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMP ifname = g_strdup_printf ("%s.%04x", obj_parent->link.name, p_key); - path = g_strdup_printf ("/sys/class/net/%s/create_child", ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name)); + path = g_strdup_printf ("/sys/class/net/%s/create_child", NM_ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name)); id = g_strdup_printf ("0x%04x", p_key); if (!nm_platform_sysctl_set (platform, path, id)) return FALSE; @@ -4977,15 +5043,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; @@ -4994,90 +5064,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); } /******************************************************************/ @@ -5085,33 +5129,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); } @@ -5120,8 +5152,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) { @@ -5142,6 +5178,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, @@ -5184,6 +5225,7 @@ ip4_address_add (NMPlatform *platform, in_addr_t peer_addr, guint32 lifetime, guint32 preferred, + guint32 flags, const char *label) { NMPObject obj_id; @@ -5196,8 +5238,8 @@ ip4_address_add (NMPlatform *platform, &addr, plen, &peer_addr, - 0, - nmp_utils_ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, + flags, + nm_utils_ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, lifetime, preferred, label); @@ -5722,6 +5764,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; @@ -5734,6 +5777,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) { @@ -5838,7 +5884,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 @@ -5854,22 +5907,22 @@ udev_device_added (NMPlatform *platform, return; } - if (g_udev_device_get_property (udev_device, "IFINDEX")) - ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); - else { - _LOGW ("(%s): udev-add: failed to get device's ifindex", ifname); + if (!g_udev_device_get_property (udev_device, "IFINDEX")) { + _LOGW ("udev-add[%s]failed to get device's ifindex", ifname); return; } + ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); if (ifindex <= 0) { - _LOGW ("(%s): udev-add: retrieved invalid IFINDEX=%d", ifname, ifindex); + _LOGW ("udev-add[%s]: retrieved invalid IFINDEX=%d", ifname, ifindex); return; } if (!g_udev_device_get_sysfs_path (udev_device)) { - _LOGD ("(%s): udev-add: couldn't determine device path; ignoring...", ifname); + _LOGD ("udev-add[%s,%d]: couldn't determine device path; ignoring...", ifname, ifindex); return; } + _LOGT ("udev-add[%s,%d]: device added", ifname, ifindex); cache_update_link_udev (platform, ifindex, udev_device); } @@ -5909,6 +5962,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; @@ -5916,6 +5970,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")); @@ -5938,15 +5995,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 @@ -5954,14 +6018,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); @@ -5993,16 +6065,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); @@ -6017,19 +6085,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_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform); + + /* 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); + 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)); + 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 @@ -6048,6 +6124,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); } @@ -6067,7 +6148,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) { @@ -6109,6 +6189,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_refresh = link_refresh; + platform_class->link_set_netns = link_set_netns; + platform_class->link_set_up = link_set_up; platform_class->link_set_down = link_set_down; platform_class->link_set_arp = link_set_arp; diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 0f2656f2..d0c92a78 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -56,7 +56,7 @@ ethtool_get (const char *name, gpointer edata) nm_assert (strlen (name) < IFNAMSIZ); memset (&ifr, 0, sizeof (ifr)); - strcpy (ifr.ifr_name, name); + nm_utils_ifname_cpy (ifr.ifr_name, name); ifr.ifr_data = edata; fd = socket (PF_INET, SOCK_DGRAM, 0); @@ -344,7 +344,7 @@ nmp_utils_mii_supports_carrier_detect (const char *ifname) } memset (&ifr, 0, sizeof (struct ifreq)); - strncpy (ifr.ifr_name, ifname, IFNAMSIZ); + nm_utils_ifname_cpy (ifr.ifr_name, ifname); errno = 0; if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) { @@ -412,114 +412,18 @@ out: return g_intern_string (driver); } -/****************************************************************** - * utils - ******************************************************************/ - -#define IPV4LL_NETWORK (htonl (0xA9FE0000L)) -#define IPV4LL_NETMASK (htonl (0xFFFF0000L)) - -gboolean -nmp_utils_ip4_address_is_link_local (in_addr_t addr) -{ - return (addr & IPV4LL_NETMASK) == IPV4LL_NETWORK; -} - -/** - * Takes a pair @timestamp and @duration, and returns the remaining duration based - * on the new timestamp @now. - */ -guint32 -nmp_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp, - guint32 duration, - guint32 now, - guint32 padding) -{ - gint64 t; - - if (duration == NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT; - - if (timestamp == 0) { - /* if the @timestamp is zero, assume it was just left unset and that the relative - * @duration starts counting from @now. This is convenient to construct an address - * and print it in nm_platform_ip4_address_to_string(). - * - * In general it does not make sense to set the @duration without anchoring at - * @timestamp because you don't know the absolute expiration time when looking - * at the address at a later moment. */ - timestamp = now; - } - - /* For timestamp > now, just accept it and calculate the expected(?) result. */ - t = (gint64) timestamp + (gint64) duration - (gint64) now; - - /* Optional padding to avoid potential races. */ - t += (gint64) padding; - - if (t <= 0) - return 0; - if (t >= NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT - 1; - return t; -} - -gboolean -nmp_utils_lifetime_get (guint32 timestamp, - guint32 lifetime, - guint32 preferred, - guint32 now, - guint32 padding, - guint32 *out_lifetime, - guint32 *out_preferred) -{ - guint32 t_lifetime, t_preferred; - - if (lifetime == 0) { - *out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - *out_preferred = NM_PLATFORM_LIFETIME_PERMANENT; - - /* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses - * (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT). - * In that case we also expect that the other fields (timestamp and preferred) are left unset. */ - g_return_val_if_fail (timestamp == 0 && preferred == 0, TRUE); - } else { - if (!now) - now = nm_utils_get_monotonic_timestamp_s (); - t_lifetime = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, padding); - if (!t_lifetime) { - *out_lifetime = 0; - *out_preferred = 0; - return FALSE; - } - t_preferred = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now, padding); - - *out_lifetime = t_lifetime; - *out_preferred = MIN (t_preferred, t_lifetime); - - /* Assert that non-permanent addresses have a (positive) @timestamp. nmp_utils_lifetime_rebase_relative_time_on_now() - * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always - * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. - */ - g_return_val_if_fail ( timestamp != 0 - || ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE); - g_return_val_if_fail (t_preferred <= t_lifetime, TRUE); - } - return TRUE; -} - gboolean nmp_utils_device_exists (const char *name) { #define SYS_CLASS_NET "/sys/class/net/" - char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ] = SYS_CLASS_NET; + char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ]; if ( !name || strlen (name) >= IFNAMSIZ || !nm_utils_is_valid_path_component (name)) g_return_val_if_reached (FALSE); - strcpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], name); + memcpy (sysdir, SYS_CLASS_NET, NM_STRLEN (SYS_CLASS_NET)); + nm_utils_ifname_cpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], name); return g_file_test (sysdir, G_FILE_TEST_EXISTS); } diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index a9d29c04..976bd8db 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -52,21 +52,6 @@ gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname); const char *nmp_utils_udev_get_driver (GUdevDevice *device); -guint32 nmp_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp, - guint32 duration, - guint32 now, - guint32 padding); - -gboolean nmp_utils_lifetime_get (guint32 timestamp, - guint32 lifetime, - guint32 preferred, - guint32 now, - guint32 padding, - guint32 *out_lifetime, - guint32 *out_preferred); - gboolean nmp_utils_device_exists (const char *name); -gboolean nmp_utils_ip4_address_is_link_local (in_addr_t addr); - #endif /* __NM_PLATFORM_UTILS_H__ */ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index e3126442..d5ee48d4 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -41,6 +41,7 @@ #include "nm-enum-types.h" #include "nm-platform-utils.h" #include "nmp-object.h" +#include "nmp-netns.h" /*****************************************************************************/ @@ -48,8 +49,6 @@ const NMIPAddr nm_ip_addr_zero = NMIPAddrInit; /*****************************************************************************/ -#define ADDRESS_LIFETIME_PADDING 5 - G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX); G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address)); G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address)); @@ -89,6 +88,7 @@ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 }; enum { PROP_0, + PROP_NETNS_SUPPORT, PROP_REGISTER_SINGLETON, LAST_PROP, }; @@ -666,6 +666,32 @@ nm_platform_link_delete (NMPlatform *self, int ifindex) } /** + * nm_platform_link_set_netns: + * @self: platform instance + * @ifindex: Interface index + * @netns_fd: the file descriptor for the new netns. + * + * Returns: %TRUE on success. + */ +gboolean +nm_platform_link_set_netns (NMPlatform *self, int ifindex, int netns_fd) +{ + const NMPlatformLink *pllink; + + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (netns_fd > 0, FALSE); + + pllink = nm_platform_link_get (self, ifindex); + if (!pllink) + return FALSE; + + _LOGD ("link: ifindex %d changing network namespace to %d", ifindex, netns_fd); + return klass->link_set_netns (self, ifindex, netns_fd); +} + +/** * nm_platform_link_get_index: * @self: platform instance * @name: Interface name @@ -1625,9 +1651,9 @@ link_option_path (NMPlatform *self, int master, const char *category, const char return NULL; return g_strdup_printf ("/sys/class/net/%s/%s/%s", - ASSERT_VALID_PATH_COMPONENT (name), - ASSERT_VALID_PATH_COMPONENT (category), - ASSERT_VALID_PATH_COMPONENT (option)); + NM_ASSERT_VALID_PATH_COMPONENT (name), + NM_ASSERT_VALID_PATH_COMPONENT (category), + NM_ASSERT_VALID_PATH_COMPONENT (option)); } static gboolean @@ -1916,7 +1942,7 @@ nm_platform_link_infiniband_get_properties (NMPlatform *self, /* Could not get the link information via netlink. To support older kernels, * fallback to reading sysfs. */ - iface = ASSERT_VALID_PATH_COMPONENT (plink->name); + iface = NM_ASSERT_VALID_PATH_COMPONENT (plink->name); /* Fall back to reading sysfs */ path = g_strdup_printf ("/sys/class/net/%s/mode", iface); @@ -2128,6 +2154,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; @@ -2368,6 +2398,52 @@ _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size) return buf; } +#define TO_STRING_IFA_FLAGS_BUF_SIZE 256 + +static const char * +_to_string_ifa_flags (guint32 ifa_flags, char *buf, gsize size) +{ +#define S_FLAGS_PREFIX " flags " + nm_assert (buf && size >= TO_STRING_IFA_FLAGS_BUF_SIZE && size > NM_STRLEN (S_FLAGS_PREFIX)); + + if (!ifa_flags) + buf[0] = '\0'; + else { + nm_platform_addr_flags2str (ifa_flags, &buf[NM_STRLEN (S_FLAGS_PREFIX)], size - NM_STRLEN (S_FLAGS_PREFIX)); + if (buf[NM_STRLEN (S_FLAGS_PREFIX)] == '\0') + buf[0] = '\0'; + else + memcpy (buf, S_FLAGS_PREFIX, NM_STRLEN (S_FLAGS_PREFIX)); + } + return buf; +} + +/******************************************************************/ + +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); +} + /******************************************************************/ void @@ -2415,6 +2491,7 @@ nm_platform_ip4_address_add (NMPlatform *self, in_addr_t peer_address, guint32 lifetime, guint32 preferred, + guint32 flags, const char *label) { _CHECK_SELF (self, klass, FALSE); @@ -2435,12 +2512,13 @@ nm_platform_ip4_address_add (NMPlatform *self, addr.timestamp = 0; /* set it at zero, which to_string will treat as *now* */ addr.lifetime = lifetime; addr.preferred = preferred; + addr.n_ifa_flags = flags; if (label) g_strlcpy (addr.label, label, sizeof (addr.label)); _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr, NULL, 0)); } - return klass->ip4_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, label); + return klass->ip4_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, flags, label); } gboolean @@ -2535,7 +2613,7 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr } static gboolean -array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint64 now, guint32 padding) +array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint32 now) { guint len = addresses ? addresses->len : 0; guint i; @@ -2548,8 +2626,8 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address && ((candidate->peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (address->plen)) == 0) { guint32 lifetime, preferred; - if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, - now, padding, &lifetime, &preferred)) + if (nm_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, &lifetime, &preferred)) return TRUE; } } @@ -2558,7 +2636,7 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address } static gboolean -array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint64 now, guint32 padding) +array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint32 now) { guint len = addresses ? addresses->len : 0; guint i; @@ -2569,8 +2647,8 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { guint32 lifetime, preferred; - if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, - now, padding, &lifetime, &preferred)) + if (nm_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, &lifetime, &preferred)) return TRUE; } } @@ -2599,7 +2677,7 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known { GArray *addresses; NMPlatformIP4Address *address; - guint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_s (); int i; _CHECK_SELF (self, klass, FALSE); @@ -2609,7 +2687,7 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known for (i = 0; i < addresses->len; i++) { address = &g_array_index (addresses, NMPlatformIP4Address, i); - if (!array_contains_ip4_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING)) + if (!array_contains_ip4_address (known_addresses, address, now)) nm_platform_ip4_address_delete (self, ifindex, address->address, address->plen, address->peer_address); } g_array_free (addresses, TRUE); @@ -2625,11 +2703,13 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); guint32 lifetime, preferred; - if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) continue; - if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, known_address->peer_address, lifetime, preferred, known_address->label)) + if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, + known_address->peer_address, lifetime, preferred, + 0, known_address->label)) return FALSE; if (out_added_addresses) { @@ -2660,7 +2740,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known { GArray *addresses; NMPlatformIP6Address *address; - guint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_s (); int i; /* Delete unknown addresses */ @@ -2672,7 +2752,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) continue; - if (!array_contains_ip6_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING)) + if (!array_contains_ip6_address (known_addresses, address, now)) nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen); } g_array_free (addresses, TRUE); @@ -2685,8 +2765,8 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); guint32 lifetime, preferred; - if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, @@ -2930,7 +3010,7 @@ _lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf, return "forever"; g_snprintf (buf, buf_size, "%usec", - nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, 0)); + nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now)); return buf; } @@ -3025,7 +3105,7 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len) str_flags->str, link->mtu, master, link->arptype, - str_if_set (str_link_type, "???"), + str_link_type ?: "???", link->kind ? (g_strcmp0 (str_link_type, link->kind) ? "/" : "*") : "?", link->kind && g_strcmp0 (str_link_type, link->kind) ? link->kind : "", link->initialized ? " init" : " not-init", @@ -3346,6 +3426,7 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize const char * nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len) { + char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; char s_address[INET_ADDRSTRLEN]; char s_peer[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; @@ -3383,10 +3464,11 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *bu str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time)); g_snprintf (buf, len, - "%s/%d lft %s pref %s%s%s%s%s src %s", + "%s/%d lft %s pref %s%s%s%s%s%s src %s", s_address, address->plen, str_lft_p, str_pref_p, str_time_p, str_peer ? str_peer : "", str_dev, + _to_string_ifa_flags (address->n_ifa_flags, s_flags, sizeof (s_flags)), str_label, source_to_string (address->source)); g_free (str_peer); @@ -3457,8 +3539,7 @@ NM_UTILS_ENUM2STR_DEFINE (nm_platform_route_scope2str, int, const char * nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len) { -#define S_FLAGS_PREFIX " flags " - char s_flags[256]; + char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; char s_address[INET6_ADDRSTRLEN]; char s_peer[INET6_ADDRSTRLEN]; char str_lft[30], str_pref[30], str_time[50]; @@ -3479,12 +3560,6 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu _to_string_dev (NULL, address->ifindex, str_dev, sizeof (str_dev)); - nm_platform_addr_flags2str (address->n_ifa_flags, &s_flags[NM_STRLEN (S_FLAGS_PREFIX)], sizeof (s_flags) - NM_STRLEN (S_FLAGS_PREFIX)); - if (s_flags[NM_STRLEN (S_FLAGS_PREFIX)] == '\0') - s_flags[0] = '\0'; - else - memcpy (s_flags, S_FLAGS_PREFIX, NM_STRLEN (S_FLAGS_PREFIX)); - str_lft_p = _lifetime_to_string (address->timestamp, address->lifetime ? address->lifetime : NM_PLATFORM_LIFETIME_PERMANENT, now, str_lft, sizeof (str_lft)), @@ -3500,7 +3575,7 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu s_address, address->plen, str_lft_p, str_pref_p, str_time_p, str_peer ? str_peer : "", str_dev, - s_flags, + _to_string_ifa_flags (address->n_ifa_flags, s_flags, sizeof (s_flags)), source_to_string (address->source)); g_free (str_peer); return buf; @@ -3825,6 +3900,7 @@ nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4A _CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, lifetime); _CMP_FIELD (a, b, preferred); + _CMP_FIELD (a, b, n_ifa_flags); _CMP_FIELD_STR (a, b, label); return 0; } @@ -3980,6 +4056,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) { @@ -4079,9 +4180,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); @@ -4110,6 +4222,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) { GObjectClass *object_class = G_OBJECT_CLASS (platform_class); @@ -4118,10 +4238,19 @@ 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, "", "", FALSE, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index b94c440a..8c97f766 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -31,6 +31,7 @@ #include "nm-core-utils.h" #include "nm-setting-vlan.h" +#include "nm-setting-wired.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -41,6 +42,7 @@ /******************************************************************/ +#define NM_PLATFORM_NETNS_SUPPORT "netns-support" #define NM_PLATFORM_REGISTER_SINGLETON "register-singleton" /******************************************************************/ @@ -177,8 +179,6 @@ typedef enum { NM_PLATFORM_SIGNAL_REMOVED, } NMPlatformSignalChangeType; -#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32 - typedef enum { /*< skip >*/ NM_PLATFORM_GET_ROUTE_FLAGS_NONE = 0, @@ -221,6 +221,11 @@ typedef struct { guint32 timestamp; \ guint32 lifetime; /* seconds since timestamp */ \ guint32 preferred; /* seconds since timestamp */ \ + \ + /* ifa_flags in 'struct ifaddrmsg' from <linux/if_addr.h>, extended to 32 bit by + * IFA_FLAGS attribute. */ \ + guint32 n_ifa_flags; \ + \ int plen; \ ; @@ -269,7 +274,6 @@ struct _NMPlatformIP6Address { __NMPlatformIPAddress_COMMON; struct in6_addr address; struct in6_addr peer_address; - guint32 n_ifa_flags; /* ifa_flags from <linux/if_addr.h>, field type "unsigned int" is as used in rtnl_addr_get_flags. */ }; typedef union { @@ -459,6 +463,8 @@ typedef struct { struct _NMPlatform { GObject parent; + + NMPNetns *_netns; }; typedef struct { @@ -485,6 +491,9 @@ typedef struct { gboolean (*link_get_unmanaged) (NMPlatform *, int ifindex, gboolean *unmanaged); gboolean (*link_refresh) (NMPlatform *, int ifindex); + + gboolean (*link_set_netns) (NMPlatform *, int ifindex, int netns_fd); + void (*process_events) (NMPlatform *self); gboolean (*link_set_up) (NMPlatform *, int ifindex, gboolean *out_no_firmware); @@ -586,6 +595,7 @@ typedef struct { in_addr_t peer_address, guint32 lifetime, guint32 preferred_lft, + guint32 flags, const char *label); gboolean (*ip6_address_add) (NMPlatform *, int ifindex, @@ -665,6 +675,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); @@ -688,6 +701,8 @@ NMPlatformError nm_platform_link_bond_add (NMPlatform *self, const char *name, c NMPlatformError nm_platform_link_team_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); gboolean nm_platform_link_delete (NMPlatform *self, int ifindex); +gboolean nm_platform_link_set_netns (NMPlatform *self, int ifindex, int netns_fd); + /* convienience methods to lookup the link and access fields of NMPlatformLink. */ int nm_platform_link_get_ifindex (NMPlatform *self, const char *name); const char *nm_platform_link_get_name (NMPlatform *self, int ifindex); @@ -853,6 +868,7 @@ gboolean nm_platform_ip4_address_add (NMPlatform *self, in_addr_t peer_address, guint32 lifetime, guint32 preferred_lft, + guint32 flags, const char *label); gboolean nm_platform_ip6_address_add (NMPlatform *self, int ifindex, @@ -925,4 +941,7 @@ const char *nm_platform_route_scope2str (int scope, char *buf, gsize len); int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b); +gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password); +gboolean nm_platform_ethtool_get_link_speed (NMPlatform *self, const char *ifname, guint32 *out_speed); + #endif /* __NETWORKMANAGER_PLATFORM_H__ */ diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c new file mode 100644 index 00000000..26295855 --- /dev/null +++ b/src/platform/nmp-netns.c @@ -0,0 +1,732 @@ +/* -*- 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 <sys/stat.h> +#include <sys/types.h> + +#include "NetworkManagerUtils.h" + +#define PROC_SELF_NS_MNT "/proc/self/ns/mnt" +#define PROC_SELF_NS_NET "/proc/self/ns/net" + +#define _CLONE_NS_ALL ((int) (CLONE_NEWNS | CLONE_NEWNET)) +#define _CLONE_NS_ALL_V CLONE_NEWNS , CLONE_NEWNET + +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_clone_ns_to_str, int, + NM_UTILS_FLAGS2STR (CLONE_NEWNS, "mnt"), + NM_UTILS_FLAGS2STR (CLONE_NEWNET, "net"), +); + +static const char * +__ns_types_to_str (int ns_types, int ns_types_already_set, char *buf, gsize len) +{ + const char *b = buf; + char bb[200]; + + nm_utils_strbuf_append_c (&buf, &len, '['); + if (ns_types & ~ns_types_already_set) { + nm_utils_strbuf_append_str (&buf, &len, + _clone_ns_to_str (ns_types & ~ns_types_already_set, bb, sizeof (bb))); + } + if (ns_types & ns_types_already_set) { + if (ns_types & ~ns_types_already_set) + nm_utils_strbuf_append_c (&buf, &len, '/'); + nm_utils_strbuf_append_str (&buf, &len, + _clone_ns_to_str (ns_types & ns_types_already_set, bb, sizeof (bb))); + } + nm_utils_strbuf_append_c (&buf, &len, ']'); + return b; +} +#define _ns_types_to_str(ns_types, ns_types_already_set, buf) \ + __ns_types_to_str (ns_types, ns_types_already_set, buf, sizeof (buf)) + +/*********************************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_PLATFORM +#define _NMLOG_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; + int ns_types; +} NetnsInfo; + +static void _stack_push (NMPNetns *netns, int ns_types); +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, _CLONE_NS_ALL); + + /* 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 NMPNetns * +_stack_current_netns (int ns_types) +{ + guint j; + + nm_assert (netns_stack && netns_stack->len > 0); + + /* we search the stack top-down to find the netns that has + * all @ns_types set. */ + for (j = netns_stack->len; ns_types && j >= 1; ) { + NetnsInfo *info; + + info = &g_array_index (netns_stack, NetnsInfo, --j); + + if (NM_FLAGS_ALL (info->ns_types, ns_types)) + return info->netns; + } + + g_return_val_if_reached (NULL); +} + +static int +_stack_current_ns_types (NMPNetns *netns, int ns_types) +{ + const int ns_types_check[] = { _CLONE_NS_ALL_V }; + guint i, j; + int res = 0; + + nm_assert (netns); + nm_assert (netns_stack && netns_stack->len > 0); + + /* we search the stack top-down to check which of @ns_types + * are already set to @netns. */ + for (j = netns_stack->len; ns_types && j >= 1; ) { + NetnsInfo *info; + + info = &g_array_index (netns_stack, NetnsInfo, --j); + if (info->netns != netns) { + ns_types = NM_FLAGS_UNSET (ns_types, info->ns_types); + continue; + } + + for (i = 0; i < G_N_ELEMENTS (ns_types_check); i++) { + if ( NM_FLAGS_HAS (ns_types, ns_types_check[i]) + && NM_FLAGS_HAS (info->ns_types, ns_types_check[i])) { + res = NM_FLAGS_SET (res, ns_types_check[i]); + ns_types = NM_FLAGS_UNSET (ns_types, ns_types_check[i]); + } + } + } + + return res; +} + +static NetnsInfo * +_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_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, int ns_types) +{ + NetnsInfo *info; + + nm_assert (netns_stack); + nm_assert (NMP_IS_NETNS (netns)); + nm_assert (NM_FLAGS_ANY (ns_types, _CLONE_NS_ALL)); + nm_assert (!NM_FLAGS_ANY (ns_types, ~_CLONE_NS_ALL)); + + g_array_set_size (netns_stack, netns_stack->len + 1); + + info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1)); + info->netns = g_object_ref (netns); + info->ns_types = ns_types; + 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 int +_setns (NMPNetns *self, int type) +{ + char buf[100]; + int fd; + + nm_assert (NM_IN_SET (type, _CLONE_NS_ALL_V)); + + fd = (type == CLONE_NEWNET) ? self->priv->fd_net : self->priv->fd_mnt; + + _LOGt (self, "set netns(%s, %d)", _ns_types_to_str (type, 0, buf), fd); + + return setns (fd, type); +} + +static gboolean +_netns_switch_push (NMPNetns *self, int ns_types) +{ + int errsv; + + if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) + && !_stack_current_ns_types (self, CLONE_NEWNET) + && _setns (self, CLONE_NEWNET) != 0) { + errsv = errno; + _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); + return FALSE; + } + if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) + && !_stack_current_ns_types (self, CLONE_NEWNS) + && _setns (self, 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 ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) + && !_stack_current_ns_types (self, CLONE_NEWNET)) { + self = _stack_current_netns (CLONE_NEWNET); + if ( self + && _setns (self, CLONE_NEWNET) != 0) { + errsv = errno; + _LOGE (self, "failed to restore netns: %s", g_strerror (errsv)); + } + } + return FALSE; + } + + return TRUE; +} + +static gboolean +_netns_switch_pop (NMPNetns *self, int ns_types) +{ + int errsv; + NMPNetns *current; + int success = TRUE; + + if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) + && (!self || !_stack_current_ns_types (self, CLONE_NEWNET))) { + current = _stack_current_netns (CLONE_NEWNET); + if (!current) { + g_warn_if_reached (); + success = FALSE; + } else if (_setns (current, CLONE_NEWNET) != 0) { + errsv = errno; + _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); + success = FALSE; + } + } + if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) + && (!self || !_stack_current_ns_types (self, CLONE_NEWNS))) { + current = _stack_current_netns (CLONE_NEWNS); + if (!current) { + g_warn_if_reached (); + success = FALSE; + } else if (_setns (current, CLONE_NEWNS) != 0) { + errsv = errno; + _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); + success = FALSE; + } + } + + return success; +} + +/*********************************************************************************************/ + +int +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; +} + +/*********************************************************************************************/ + +static gboolean +_nmp_netns_push_type (NMPNetns *self, int ns_types) +{ + NetnsInfo *info; + char sbuf[100]; + + _stack_ensure_init (); + + info = _stack_peek (); + g_return_val_if_fail (info, FALSE); + + if (info->netns == self && info->ns_types == ns_types) { + info->count++; + _LOGt (self, "push#%u* %s (increase count to %d)", + _stack_size () - 1, + _ns_types_to_str (ns_types, ns_types, sbuf), info->count); + return TRUE; + } + + _LOGD (self, "push#%u %s", + _stack_size (), + _ns_types_to_str (ns_types, + _stack_current_ns_types (self, ns_types), + sbuf)); + + if (!_netns_switch_push (self, ns_types)) + return FALSE; + + _stack_push (self, ns_types); + return TRUE; +} + +gboolean +nmp_netns_push (NMPNetns *self) +{ + g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); + + return _nmp_netns_push_type (self, _CLONE_NS_ALL); +} + +gboolean +nmp_netns_push_type (NMPNetns *self, int ns_types) +{ + g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); + g_return_val_if_fail (!NM_FLAGS_ANY (ns_types, ~_CLONE_NS_ALL), FALSE); + + return _nmp_netns_push_type (self, ns_types == 0 ? _CLONE_NS_ALL : ns_types); +} + +NMPNetns * +nmp_netns_new (void) +{ + 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_NS_ALL) != 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) != 0) { + errsv = errno; + _LOGE (NULL, "failed mount --make-rslave: %s", g_strerror (errsv)); + goto err_out; + } + + if (umount2 ("/sys", MNT_DETACH) != 0) { + errsv = errno; + _LOGE (NULL, "failed umount /sys: %s", g_strerror (errsv)); + goto err_out; + } + + if (mount ("sysfs", "/sys", "sysfs", 0, NULL) != 0) { + errsv = errno; + _LOGE (NULL, "failed mount /sys: %s", g_strerror (errsv)); + 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, _CLONE_NS_ALL); + + return self; +err_out: + _netns_switch_pop (NULL, _CLONE_NS_ALL); + return NULL; +} + +gboolean +nmp_netns_pop (NMPNetns *self) +{ + NetnsInfo *info; + int ns_types; + + 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#%u* (decrease count to %d)", + _stack_size () - 1, 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#%u", _stack_size () - 1); + + ns_types = info->ns_types; + + _stack_pop (); + + return _netns_switch_pop (self, ns_types); +} + +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 (); +} + +/*********************************************************************************************/ + +gboolean +nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) +{ + gs_free char *dirname = NULL; + int errsv; + int fd; + nm_auto_pop_netns NMPNetns *netns_pop = NULL; + + g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); + g_return_val_if_fail (filename && filename[0] == '/', FALSE); + + if (!nmp_netns_push_type (self, CLONE_NEWNET)) + return FALSE; + netns_pop = self; + + dirname = g_path_get_dirname (filename); + if (mkdir (dirname, 0) != 0) { + errsv = errno; + if (errsv != EEXIST) { + _LOGE (self, "bind: failed to create directory %s: %s", + dirname, g_strerror (errsv)); + return FALSE; + } + } + + if ((fd = creat (filename, S_IRUSR | S_IRGRP | S_IROTH)) == -1) { + errsv = errno; + _LOGE (self, "bind: failed to create %s: %s", + filename, g_strerror (errsv)); + return FALSE; + } + close (fd); + + if (mount (PROC_SELF_NS_NET, filename, "none", MS_BIND, NULL) != 0) { + errsv = errno; + _LOGE (self, "bind: failed to mount %s to %s: %s", + PROC_SELF_NS_NET, filename, g_strerror (errsv)); + unlink (filename); + return FALSE; + } + + if (out_fd) { + if ((fd = open (filename, O_RDONLY)) == -1) { + errsv = errno; + _LOGE (self, "bind: failed to open %s: %s", filename, g_strerror (errsv)); + umount2 (filename, MNT_DETACH); + unlink (filename); + return FALSE; + } + *out_fd = fd; + } + + return TRUE; +} + +gboolean +nmp_netns_bind_to_path_destroy (NMPNetns *self, const char *filename) +{ + int errsv; + + g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); + g_return_val_if_fail (filename && filename[0] == '/', FALSE); + + if (umount2 (filename, MNT_DETACH) != 0) { + errsv = errno; + _LOGE (self, "bind: failed to unmount2 %s: %s", filename, g_strerror (errsv)); + return FALSE; + } + if (unlink (filename) != 0) { + errsv = errno; + _LOGE (self, "bind: failed to unlink %s: %s", filename, g_strerror (errsv)); + return FALSE; + } + return TRUE; +} + +/******************************************************************************/ + +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); +} diff --git a/src/platform/nmp-netns.h b/src/platform/nmp-netns.h new file mode 100644 index 00000000..4eac07ac --- /dev/null +++ b/src/platform/nmp-netns.h @@ -0,0 +1,74 @@ +/* -*- 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_push_type (NMPNetns *self, int ns_types); +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))) + +gboolean nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd); +gboolean nmp_netns_bind_to_path_destroy (NMPNetns *self, const char *filename); + +#endif /* __NMP_NETNS_UTILS_H__ */ diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index b7b04490..adeb3aab 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -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; } @@ -1192,12 +1188,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) { g_return_val_if_fail (cache, TRUE); @@ -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; } diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 7758798f..6d5b9627 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -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__ */ diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 3b52a7be..83a0bfd3 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -94,12 +94,12 @@ test_ip4_address_general (void) /* Add address */ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); - nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal (address_added); /* Add address again (aka update) */ - nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime + 100, preferred + 50, NULL); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime + 100, preferred + 50, 0, NULL); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -197,7 +197,7 @@ test_ip4_address_general_2 (void) g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, DEVICE_IFINDEX, NULL)); /* Add/delete notification */ - nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); accept_signal (address_added); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr); @@ -205,7 +205,7 @@ test_ip4_address_general_2 (void) g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); /* Add/delete conflict */ - nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal (address_added); @@ -273,7 +273,7 @@ test_ip4_address_peer (void) accept_signals (address_added, 0, G_MAXINT); /* Add/delete notification */ - nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer, lifetime, preferred, NULL); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer, lifetime, preferred, 0, NULL); accept_signal (address_added); a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer); g_assert (a); @@ -281,7 +281,7 @@ test_ip4_address_peer (void) nmtstp_ip_address_assert_lifetime ((NMPlatformIPAddress *) a, -1, lifetime, preferred); - nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer2, lifetime, preferred, NULL); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer2, lifetime, preferred, 0, NULL); accept_signal (address_added); g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2); @@ -328,7 +328,7 @@ test_ip4_address_peer_zero (void) for (i = 0; i < G_N_ELEMENTS (peers); i++) { g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i])); - nmtstp_ip4_address_add (EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, label); + nmtstp_ip4_address_add (EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, 0, label); addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); g_assert (addrs); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 6ad24478..4036daad 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -63,7 +63,7 @@ test_cleanup_internal (void) g_assert (ifindex > 0); /* Add routes and addresses */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, NULL)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL)); g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 268a5c92..e9fffe90 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -338,30 +338,32 @@ _wait_for_signal_timeout (gpointer user_data) } gboolean -nmtstp_wait_for_signal (guint timeout_ms) +nmtstp_wait_for_signal (NMPlatform *platform, guint timeout_ms) { WaitForSignalData data = { 0 }; - gulong id_link, id_ip4_address, id_ip6_address, id_ip4_route, id_ip6_route; + if (!platform) + platform = NM_PLATFORM_GET; + data.loop = g_main_loop_new (NULL, FALSE); - id_link = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); - id_ip4_address = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); - id_ip6_address = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); - id_ip4_route = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); - id_ip6_route = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_link = g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip4_address = g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip6_address = g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip4_route = g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip6_route = g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); if (timeout_ms != 0) data.id = g_timeout_add (timeout_ms, _wait_for_signal_timeout, &data); g_main_loop_run (data.loop); - g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_link)); - g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip4_address)); - g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip6_address)); - g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip4_route)); - g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip6_route)); + g_assert (nm_clear_g_signal_handler (platform, &id_link)); + g_assert (nm_clear_g_signal_handler (platform, &id_ip4_address)); + g_assert (nm_clear_g_signal_handler (platform, &id_ip6_address)); + g_assert (nm_clear_g_signal_handler (platform, &id_ip4_route)); + g_assert (nm_clear_g_signal_handler (platform, &id_ip6_route)); if (nm_clear_g_source (&data.id)) g_assert (timeout_ms != 0 && !data.timeout); @@ -372,7 +374,7 @@ nmtstp_wait_for_signal (guint timeout_ms) } gboolean -nmtstp_wait_for_signal_until (gint64 until_ms) +nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms) { gint64 now; @@ -382,19 +384,19 @@ nmtstp_wait_for_signal_until (gint64 until_ms) if (until_ms < now) return FALSE; - if (nmtstp_wait_for_signal (MAX (1, until_ms - now))) + if (nmtstp_wait_for_signal (platform, MAX (1, until_ms - now))) return TRUE; } } const NMPlatformLink * -nmtstp_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms) +nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms) { - return nmtstp_wait_for_link_until (ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); + return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); } const NMPlatformLink * -nmtstp_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms) +nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms) { const NMPlatformLink *plink; gint64 now; @@ -402,7 +404,7 @@ nmtstp_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, g while (TRUE) { now = nm_utils_get_monotonic_timestamp_ms (); - plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname); + plink = nm_platform_link_get_by_ifname (platform ?: NM_PLATFORM_GET, ifname); if ( plink && (expected_link_type == NM_LINK_TYPE_NONE || plink->type == expected_link_type)) return plink; @@ -410,22 +412,22 @@ nmtstp_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, g if (until_ms < now) return NULL; - nmtstp_wait_for_signal (MAX (1, until_ms - now)); + nmtstp_wait_for_signal (platform, MAX (1, until_ms - now)); } } const NMPlatformLink * -nmtstp_assert_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms) +nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms) { - return nmtstp_assert_wait_for_link_until (ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); + return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); } const NMPlatformLink * -nmtstp_assert_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms) +nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms) { const NMPlatformLink *plink; - plink = nmtstp_wait_for_link_until (ifname, expected_link_type, until_ms); + plink = nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms); g_assert (plink); return plink; } @@ -563,8 +565,8 @@ _ip_address_add (gboolean external_command, const NMIPAddr *peer_address, guint32 lifetime, guint32 preferred, - const char *label, - guint32 flags) + guint32 flags, + const char *label) { gint64 end_time; @@ -626,7 +628,6 @@ _ip_address_add (gboolean external_command, gboolean success; if (is_v4) { - g_assert (flags == 0); success = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address->addr4, @@ -634,6 +635,7 @@ _ip_address_add (gboolean external_command, peer_address->addr4, lifetime, preferred, + flags, label); } else { g_assert (label == NULL); @@ -686,20 +688,20 @@ _ip_address_add (gboolean external_command, /* for internal command, we expect not to reach this line.*/ g_assert (external_command); - g_assert (nmtstp_wait_for_signal_until (end_time)); + g_assert (nmtstp_wait_for_signal_until (NM_PLATFORM_GET, end_time)); } while (TRUE); } -#define _assert_pllink(success, pllink, name, type) \ +#define _assert_pllink(platform, success, pllink, name, type) \ G_STMT_START { \ const NMPlatformLink *_pllink = (pllink); \ \ if ((success)) { \ g_assert (_pllink); \ - g_assert (_pllink == nmtstp_link_get_typed (_pllink->ifindex, (name), (type))); \ + g_assert (_pllink == nmtstp_link_get_typed (platform, _pllink->ifindex, (name), (type))); \ } else { \ g_assert (!_pllink); \ - g_assert (!nmtstp_link_get (0, (name))); \ + g_assert (!nmtstp_link_get (platform, 0, (name))); \ } \ } G_STMT_END @@ -718,12 +720,12 @@ nmtstp_link_dummy_add (gboolean external_command, success = !nmtstp_run_command ("ip link add %s type dummy", name); if (success) - pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_DUMMY, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, NM_LINK_TYPE_DUMMY, 100); } else success = nm_platform_link_dummy_add (NM_PLATFORM_GET, name, &pllink) == NM_PLATFORM_ERROR_SUCCESS; g_assert (success); - _assert_pllink (success, pllink, name, NM_LINK_TYPE_DUMMY); + _assert_pllink (NM_PLATFORM_GET, success, pllink, name, NM_LINK_TYPE_DUMMY); return pllink; } @@ -755,11 +757,11 @@ nmtstp_link_gre_add (gboolean external_command, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); if (success) - pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_GRE, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, NM_LINK_TYPE_GRE, 100); } else success = nm_platform_link_gre_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; - _assert_pllink (success, pllink, name, NM_LINK_TYPE_GRE); + _assert_pllink (NM_PLATFORM_GET, success, pllink, name, NM_LINK_TYPE_GRE); return pllink; } @@ -806,11 +808,11 @@ nmtstp_link_ip6tnl_add (gboolean external_command, lnk->encap_limit, lnk->flow_label); if (success) - pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IP6TNL, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, NM_LINK_TYPE_IP6TNL, 100); } else success = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; - _assert_pllink (success, pllink, name, NM_LINK_TYPE_IP6TNL); + _assert_pllink (NM_PLATFORM_GET, success, pllink, name, NM_LINK_TYPE_IP6TNL); return pllink; } @@ -843,11 +845,11 @@ nmtstp_link_ipip_add (gboolean external_command, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); if (success) - pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IPIP, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, NM_LINK_TYPE_IPIP, 100); } else success = nm_platform_link_ipip_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; - _assert_pllink (success, pllink, name, NM_LINK_TYPE_IPIP); + _assert_pllink (NM_PLATFORM_GET, success, pllink, name, NM_LINK_TYPE_IPIP); return pllink; } @@ -888,11 +890,11 @@ nmtstp_link_macvlan_add (gboolean external_command, modes[lnk->mode], lnk->no_promisc ? "nopromisc" : ""); if (success) - pllink = nmtstp_assert_wait_for_link (name, link_type, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, link_type, 100); } else success = nm_platform_link_macvlan_add (NM_PLATFORM_GET, name, parent, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; - _assert_pllink (success, pllink, name, link_type); + _assert_pllink (NM_PLATFORM_GET, success, pllink, name, link_type); return pllink; } @@ -930,11 +932,11 @@ nmtstp_link_sit_add (gboolean external_command, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); if (success) - pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_SIT, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, NM_LINK_TYPE_SIT, 100); } else success = nm_platform_link_sit_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; - _assert_pllink (success, pllink, name, NM_LINK_TYPE_SIT); + _assert_pllink (NM_PLATFORM_GET, success, pllink, name, NM_LINK_TYPE_SIT); return pllink; } @@ -983,7 +985,7 @@ nmtstp_link_vxlan_add (gboolean external_command, /* Older versions of iproute2 don't support adding vxlan devices. * On failure, fallback to using platform code. */ if (err == 0) - pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_VXLAN, 100); + pllink = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, name, NM_LINK_TYPE_VXLAN, 100); else _LOGI ("Adding vxlan device via iproute2 failed. Assume iproute2 is not up to the task."); } @@ -1006,6 +1008,7 @@ nmtstp_ip4_address_add (gboolean external_command, in_addr_t peer_address, guint32 lifetime, guint32 preferred, + guint32 flags, const char *label) { _ip_address_add (external_command, @@ -1016,8 +1019,8 @@ nmtstp_ip4_address_add (gboolean external_command, (NMIPAddr *) &peer_address, lifetime, preferred, - label, - 0); + flags, + label); } void @@ -1038,8 +1041,8 @@ nmtstp_ip6_address_add (gboolean external_command, (NMIPAddr *) &peer_address, lifetime, preferred, - NULL, - flags); + flags, + NULL); } static void @@ -1127,7 +1130,7 @@ _ip_address_del (gboolean external_command, /* for internal command, we expect not to reach this line.*/ g_assert (external_command); - g_assert (nmtstp_wait_for_signal_until (end_time)); + g_assert (nmtstp_wait_for_signal_until (NM_PLATFORM_GET, end_time)); } while (TRUE); } @@ -1161,14 +1164,18 @@ nmtstp_ip6_address_del (gboolean external_command, } const NMPlatformLink * -nmtstp_link_get_typed (int ifindex, +nmtstp_link_get_typed (NMPlatform *platform, + int ifindex, const char *name, NMLinkType link_type) { const NMPlatformLink *pllink = NULL; + if (!platform) + platform = NM_PLATFORM_GET; + if (ifindex > 0) { - pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); + pllink = nm_platform_link_get (platform, ifindex); if (pllink) { g_assert_cmpint (pllink->ifindex, ==, ifindex); @@ -1176,12 +1183,12 @@ nmtstp_link_get_typed (int ifindex, g_assert_cmpstr (name, ==, pllink->name); } else { if (name) - g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name)); + g_assert (!nm_platform_link_get_by_ifname (platform, name)); } } else { g_assert (name); - pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name); + pllink = nm_platform_link_get_by_ifname (platform, name); if (pllink) g_assert_cmpstr (name, ==, pllink->name); @@ -1196,10 +1203,11 @@ nmtstp_link_get_typed (int ifindex, } const NMPlatformLink * -nmtstp_link_get (int ifindex, +nmtstp_link_get (NMPlatform *platform, + int ifindex, const char *name) { - return nmtstp_link_get_typed (ifindex, name, NM_LINK_TYPE_NONE); + return nmtstp_link_get_typed (platform, ifindex, name, NM_LINK_TYPE_NONE); } void @@ -1212,7 +1220,7 @@ nmtstp_link_del (gboolean external_command, gboolean success; gs_free char *name_copy = NULL; - pllink = nmtstp_link_get (ifindex, name); + pllink = nmtstp_link_get (NM_PLATFORM_GET, ifindex, name); g_assert (pllink); @@ -1242,7 +1250,7 @@ nmtstp_link_del (gboolean external_command, /* for internal command, we expect not to reach this line.*/ g_assert (external_command); - g_assert (nmtstp_wait_for_signal_until (end_time)); + g_assert (nmtstp_wait_for_signal_until (NM_PLATFORM_GET, end_time)); } while (TRUE); } @@ -1288,7 +1296,7 @@ nmtstp_link_set_updown (gboolean external_command, /* for internal command, we expect not to reach this line.*/ g_assert (external_command); - g_assert (nmtstp_wait_for_signal_until (end_time)); + g_assert (nmtstp_wait_for_signal_until (NM_PLATFORM_GET, end_time)); } while (TRUE); } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 0281d3c5..82561193 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -91,13 +91,13 @@ void link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, N int nmtstp_run_command (const char *format, ...) __attribute__((__format__ (__printf__, 1, 2))); #define nmtstp_run_command_check(...) do { g_assert_cmpint (nmtstp_run_command (__VA_ARGS__), ==, 0); } while (0) -gboolean nmtstp_wait_for_signal (guint timeout_ms); -gboolean nmtstp_wait_for_signal_until (gint64 until_ms); -const NMPlatformLink *nmtstp_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms); -const NMPlatformLink *nmtstp_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms); +gboolean nmtstp_wait_for_signal (NMPlatform *platform, guint timeout_ms); +gboolean nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms); +const NMPlatformLink *nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms); +const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms); -const NMPlatformLink *nmtstp_assert_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms); -const NMPlatformLink *nmtstp_assert_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms); +const NMPlatformLink *nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms); +const NMPlatformLink *nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms); int nmtstp_run_command_check_external_global (void); gboolean nmtstp_run_command_check_external (int external_command); @@ -117,6 +117,7 @@ void nmtstp_ip4_address_add (gboolean external_command, in_addr_t peer_address, guint32 lifetime, guint32 preferred, + guint32 flags, const char *label); void nmtstp_ip6_address_add (gboolean external_command, int ifindex, @@ -125,7 +126,7 @@ void nmtstp_ip6_address_add (gboolean external_command, struct in6_addr peer_address, guint32 lifetime, guint32 preferred, - guint flags); + guint32 flags); void nmtstp_ip4_address_del (gboolean external_command, int ifindex, in_addr_t address, @@ -136,8 +137,8 @@ void nmtstp_ip6_address_del (gboolean external_command, struct in6_addr address, int plen); -const NMPlatformLink *nmtstp_link_get_typed (int ifindex, const char *name, NMLinkType link_type); -const NMPlatformLink *nmtstp_link_get (int ifindex, const char *name); +const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type); +const NMPlatformLink *nmtstp_link_get (NMPlatform *platform, int ifindex, const char *name); void nmtstp_link_set_updown (gboolean external_command, int ifindex, diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c index f342e565..66f72fa5 100644 --- a/src/platform/tests/test-general.c +++ b/src/platform/tests/test-general.c @@ -18,12 +18,12 @@ * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-platform-utils.h" +#include "nm-default.h" #include <linux/rtnetlink.h> +#include "nm-platform-utils.h" #include "nm-linux-platform.h" -#include "nm-default.h" #include "nm-test-utils.h" diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 3fa5ad50..94695edc 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -21,8 +21,13 @@ #include "nm-default.h" #include <sched.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/types.h> #include "nmp-object.h" +#include "nmp-netns.h" +#include "nm-platform-utils.h" #include "test-common.h" #include "nm-test-utils.h" @@ -40,6 +45,9 @@ #define VLAN_FLAGS 0 #define MTU 1357 +#define _ADD_DUMMY(platform, name) \ + g_assert_cmpint (nm_platform_link_dummy_add ((platform), (name), NULL), ==, NM_PLATFORM_ERROR_SUCCESS) + static void test_bogus(void) { @@ -52,16 +60,16 @@ test_bogus(void) g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_get_type_name (NM_PLATFORM_GET, BOGUS_IFINDEX)); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *"); g_assert (!nm_platform_link_set_up (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL)); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *"); g_assert (!nm_platform_link_set_down (NM_PLATFORM_GET, BOGUS_IFINDEX)); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *"); g_assert (!nm_platform_link_set_arp (NM_PLATFORM_GET, BOGUS_IFINDEX)); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *"); g_assert (!nm_platform_link_set_noarp (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, BOGUS_IFINDEX)); @@ -72,7 +80,7 @@ test_bogus(void) g_assert (!addrlen); g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL)); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*failure changing link: *"); g_assert (!nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU)); g_assert (!nm_platform_link_get_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX)); @@ -690,7 +698,7 @@ test_software_detect (gconstpointer user_data) const gboolean ext = test_data->external_command; nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); - ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; + ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; switch (test_data->link_type) { case NM_LINK_TYPE_GRE: { @@ -852,7 +860,7 @@ test_software_detect (gconstpointer user_data) g_assert_not_reached (); } - ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, test_data->link_type, 100)->ifindex; + ifindex = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, DEVICE_NAME, test_data->link_type, 100)->ifindex; nmtstp_link_set_updown (-1, ifindex_parent, TRUE); @@ -1137,10 +1145,10 @@ test_vlan_set_xgress (void) int ifindex, ifindex_parent; nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); - ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; + ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1245", DEVICE_NAME, PARENT_NAME); - ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex; + ifindex = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex; /* ingress-qos-map */ @@ -1662,7 +1670,7 @@ test_create_many_links (gconstpointer user_data) guint n_devices = GPOINTER_TO_UINT (user_data); if (n_devices > 100 && nmtst_test_quick ()) { - g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", str_if_set (g_get_prgname (), "test-link-linux")); + g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", g_get_prgname () ?: "test-link-linux"); g_test_skip ("Skip long running test"); return; } @@ -1685,8 +1693,8 @@ test_nl_bugs_veth (void) /* create veth pair. */ nmtstp_run_command_check ("ip link add dev %s type veth peer name %s", IFACE_VETH0, IFACE_VETH1); - ifindex_veth0 = nmtstp_assert_wait_for_link (IFACE_VETH0, NM_LINK_TYPE_VETH, 100)->ifindex; - ifindex_veth1 = nmtstp_assert_wait_for_link (IFACE_VETH1, NM_LINK_TYPE_VETH, 100)->ifindex; + ifindex_veth0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_VETH0, NM_LINK_TYPE_VETH, 100)->ifindex; + ifindex_veth1 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_VETH1, NM_LINK_TYPE_VETH, 100)->ifindex; /* assert that nm_platform_link_veth_get_properties() returns the expected peer ifindexes. */ g_assert (nm_platform_link_veth_get_properties (NM_PLATFORM_GET, ifindex_veth0, &i)); @@ -1722,7 +1730,7 @@ test_nl_bugs_veth (void) nmtstp_run_command_check ("ip link set %s netns %ld", IFACE_VETH1, (long) nmtstp_namespace_handle_get_pid (ns_handle)); NMTST_WAIT_ASSERT (100, { - nmtstp_wait_for_signal (50); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); nm_platform_process_events (NM_PLATFORM_GET); pllink_veth1 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth1); @@ -1736,8 +1744,8 @@ test_nl_bugs_veth (void) out: nmtstp_link_del (-1, ifindex_veth0, IFACE_VETH0); - g_assert (!nmtstp_link_get (ifindex_veth0, IFACE_VETH0)); - g_assert (!nmtstp_link_get (ifindex_veth1, IFACE_VETH1)); + g_assert (!nmtstp_link_get (NM_PLATFORM_GET, ifindex_veth0, IFACE_VETH0)); + g_assert (!nmtstp_link_get (NM_PLATFORM_GET, ifindex_veth1, IFACE_VETH1)); nmtstp_namespace_handle_release (ns_handle); } @@ -1755,16 +1763,16 @@ test_nl_bugs_spuroius_newlink (void) /* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */ nmtstp_run_command_check ("ip link add %s type dummy", IFACE_DUMMY0); - ifindex_dummy0 = nmtstp_assert_wait_for_link (IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex; + ifindex_dummy0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex; nmtstp_run_command_check ("ip link add %s type bond", IFACE_BOND0); - ifindex_bond0 = nmtstp_assert_wait_for_link (IFACE_BOND0, NM_LINK_TYPE_BOND, 100)->ifindex; + ifindex_bond0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_BOND0, NM_LINK_TYPE_BOND, 100)->ifindex; nmtstp_link_set_updown (-1, ifindex_bond0, TRUE); nmtstp_run_command_check ("ip link set %s master %s", IFACE_DUMMY0, IFACE_BOND0); NMTST_WAIT_ASSERT (100, { - nmtstp_wait_for_signal (50); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0); g_assert (pllink); @@ -1775,7 +1783,7 @@ test_nl_bugs_spuroius_newlink (void) nmtstp_run_command_check ("ip link del %s", IFACE_BOND0); wait_for_settle = TRUE; - nmtstp_wait_for_signal (50); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); again: nm_platform_process_events (NM_PLATFORM_GET); pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_bond0); @@ -1783,11 +1791,11 @@ again: if (wait_for_settle) { wait_for_settle = FALSE; - NMTST_WAIT (300, { nmtstp_wait_for_signal (50); }); + NMTST_WAIT (300, { nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); }); goto again; } - g_assert (!nmtstp_link_get (ifindex_bond0, IFACE_BOND0)); + g_assert (!nmtstp_link_get (NM_PLATFORM_GET, ifindex_bond0, IFACE_BOND0)); nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0); } @@ -1805,16 +1813,16 @@ test_nl_bugs_spuroius_dellink (void) /* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */ nmtstp_run_command_check ("ip link add %s type dummy", IFACE_DUMMY0); - ifindex_dummy0 = nmtstp_assert_wait_for_link (IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex; + ifindex_dummy0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex; nmtstp_run_command_check ("ip link add %s type bridge", IFACE_BRIDGE0); - ifindex_bridge0 = nmtstp_assert_wait_for_link (IFACE_BRIDGE0, NM_LINK_TYPE_BRIDGE, 100)->ifindex; + ifindex_bridge0 = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, IFACE_BRIDGE0, NM_LINK_TYPE_BRIDGE, 100)->ifindex; nmtstp_link_set_updown (-1, ifindex_bridge0, TRUE); nmtstp_run_command_check ("ip link set %s master %s", IFACE_DUMMY0, IFACE_BRIDGE0); NMTST_WAIT_ASSERT (100, { - nmtstp_wait_for_signal (50); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0); g_assert (pllink); @@ -1827,7 +1835,7 @@ test_nl_bugs_spuroius_dellink (void) nmtstp_run_command_check ("ip link set %s nomaster", IFACE_DUMMY0); wait_for_settle = TRUE; - nmtstp_wait_for_signal (50); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); again: nm_platform_process_events (NM_PLATFORM_GET); pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_bridge0); @@ -1838,7 +1846,7 @@ again: if (wait_for_settle) { wait_for_settle = FALSE; - NMTST_WAIT (300, { nmtstp_wait_for_signal (50); }); + NMTST_WAIT (300, { nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); }); goto again; } @@ -1846,6 +1854,442 @@ again: nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0); } +/******************************************************************/ + +static void +_test_netns_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_teardown (gpointer fixture, gconstpointer test_data) +{ + /* re-create platform instance */ + SETUP (); +} + +static NMPlatform * +_test_netns_create_platform (void) +{ + NMPNetns *netns; + NMPlatform *platform; + + netns = nmp_netns_new (); + g_assert (NMP_IS_NETNS (netns)); + + platform = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL); + g_assert (NM_IS_LINUX_PLATFORM (platform)); + + nmp_netns_pop (netns); + g_object_unref (netns); + + return platform; +} + +static gboolean +_test_netns_check_skip (void) +{ + static int support = -1; + static int support_errsv = 0; + NMPNetns *netns; + + netns = nmp_netns_get_current (); + if (!netns) { + g_test_skip ("No netns support"); + return TRUE; + } + + g_assert (nmp_netns_get_fd_net (netns) > 0); + + if (support == -1) { + support = (setns (nmp_netns_get_fd_net (netns), CLONE_NEWNET) == 0); + if (!support) + support_errsv = errno; + } + if (!support) { + _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); + g_test_skip ("No netns support (setns failed)"); + return TRUE; + } + return FALSE; +} + +/******************************************************************/ + +static void +test_netns_general (gpointer fixture, gconstpointer test_data) +{ + gs_unref_object NMPlatform *platform_1 = NULL; + gs_unref_object NMPlatform *platform_2 = NULL; + NMPNetns *netns_tmp; + char sbuf[100]; + int i, j, k; + gboolean ethtool_support; + + if (_test_netns_check_skip ()) + return; + + platform_1 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL); + platform_2 = _test_netns_create_platform (); + + /* 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"); + + 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)); + } + + g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy1_/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_1, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex)); + g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_1, 0, "dummy2a", NM_LINK_TYPE_DUMMY)->ifindex)); + g_assert_cmpstr (nm_platform_sysctl_get (platform_1, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, NULL); + + g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy1_/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_2, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex)); + g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2a/ifindex"), ==, NULL); + g_assert_cmpstr (nm_platform_sysctl_get (platform_2, "/sys/devices/virtual/net/dummy2b/ifindex"), ==, nm_sprintf_buf (sbuf, "%d", nmtstp_link_get_typed (platform_2, 0, "dummy2b", NM_LINK_TYPE_DUMMY)->ifindex)); + + for (i = 0; i < 10; i++) { + 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)); + + 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); +} + +/*****************************************************************************/ + +static void +test_netns_set_netns (gpointer fixture, gconstpointer test_data) +{ + NMPlatform *platforms[3]; + gs_unref_object NMPlatform *platform_0 = NULL; + gs_unref_object NMPlatform *platform_1 = NULL; + gs_unref_object NMPlatform *platform_2 = NULL; + nm_auto_pop_netns NMPNetns *netns_pop = NULL; + int i; + + if (_test_netns_check_skip ()) + return; + + platforms[0] = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL); + platforms[1] = platform_1 = _test_netns_create_platform (); + platforms[2] = platform_2 = _test_netns_create_platform (); + + i = nmtst_get_rand_int () % 4; + if (i != 3) + g_assert (nm_platform_netns_push (platforms[i], &netns_pop)); + +#define LINK_MOVE_NAME "link-move" + g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME)); + g_assert (!nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME)); + _ADD_DUMMY (platform_1, LINK_MOVE_NAME); + g_assert ( nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME)); + g_assert (!nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME)); + g_assert (nm_platform_link_set_netns (platform_1, + nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME)->ifindex, + nmp_netns_get_fd_net (nm_platform_netns_get (platform_2)))); + g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME)); + g_assert (!nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME)); + nmtstp_assert_wait_for_link (platform_2, LINK_MOVE_NAME, NM_LINK_TYPE_DUMMY, 100); + g_assert (!nm_platform_link_get_by_ifname (platform_1, LINK_MOVE_NAME)); + g_assert ( nm_platform_link_get_by_ifname (platform_2, LINK_MOVE_NAME)); +} + +/*****************************************************************************/ + +static char * +_get_current_namespace_id (int ns_type) +{ + const char *p; + GError *error = NULL; + char *id; + + switch (ns_type) { + case CLONE_NEWNET: + p = "/proc/self/ns/net"; + break; + case CLONE_NEWNS: + p = "/proc/self/ns/mnt"; + break; + default: + g_assert_not_reached (); + } + + id = g_file_read_link (p, &error); + g_assert_no_error (error); + g_assert (id); + return id; +} + +static char * +_get_sysctl_value (const char *path) +{ + char *data = NULL; + gs_free_error GError *error = NULL; + + if (!g_file_get_contents (path, &data, NULL, &error)) { + nmtst_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, NULL); + g_assert (!data); + } else { + g_assert_no_error (error); + g_assert (data); + g_strstrip (data); + } + return data; +} + +static void +test_netns_push (gpointer fixture, gconstpointer test_data) +{ + gs_unref_object NMPlatform *platform_0 = NULL; + gs_unref_object NMPlatform *platform_1 = NULL; + gs_unref_object NMPlatform *platform_2 = NULL; + nm_auto_pop_netns NMPNetns *netns_pop = NULL; + gs_unref_ptrarray GPtrArray *device_names = g_ptr_array_new_with_free_func (g_free); + int i, j; + const int ns_types_list[] = { CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWNET | CLONE_NEWNS }; + const int ns_types_test[] = { CLONE_NEWNET, CLONE_NEWNS }; + typedef struct { + NMPlatform *platform; + const char *device_name; + const char *sysctl_path; + const char *sysctl_value; + const char *ns_net; + const char *ns_mnt; + } PlatformData; + PlatformData pl[3] = { }; + PlatformData *pl_base; + struct { + PlatformData *pl; + int ns_types; + } stack[6] = { }; + int nstack; + + if (_test_netns_check_skip ()) + return; + + pl[0].platform = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL); + pl[1].platform = platform_1 = _test_netns_create_platform (); + pl[2].platform = platform_2 = _test_netns_create_platform (); + + pl_base = &pl[0]; + i = nmtst_get_rand_int () % (G_N_ELEMENTS (pl) + 1); + if (i < G_N_ELEMENTS (pl)) { + pl_base = &pl[i]; + g_assert (nm_platform_netns_push (pl[i].platform, &netns_pop)); + } + + for (i = 0; i < G_N_ELEMENTS (pl); i++) { + nm_auto_pop_netns NMPNetns *netns_free = NULL; + char *tmp; + + g_assert (nm_platform_netns_push (pl[i].platform, &netns_free)); + + tmp = g_strdup_printf ("nmtst-dev-%d", i); + g_ptr_array_add (device_names, tmp); + pl[i].device_name = tmp; + + tmp = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", pl[i].device_name); + g_ptr_array_add (device_names, tmp); + pl[i].sysctl_path = tmp; + + pl[i].sysctl_value = nmtst_get_rand_int () % 2 ? "1" : "0"; + + _ADD_DUMMY (pl[i].platform, pl[i].device_name); + + g_assert (nm_platform_sysctl_set (pl[i].platform, pl[i].sysctl_path, pl[i].sysctl_value)); + + tmp = _get_current_namespace_id (CLONE_NEWNET); + g_ptr_array_add (device_names, tmp); + pl[i].ns_net = tmp; + + tmp = _get_current_namespace_id (CLONE_NEWNS); + g_ptr_array_add (device_names, tmp); + pl[i].ns_mnt = tmp; + } + + nstack = nmtst_get_rand_int () % (G_N_ELEMENTS (stack) + 1); + for (i = 0; i < nstack; i++) { + stack[i].pl = &pl[nmtst_get_rand_int () % G_N_ELEMENTS (pl)]; + stack[i].ns_types = ns_types_list[nmtst_get_rand_int () % G_N_ELEMENTS (ns_types_list)]; + + nmp_netns_push_type (nm_platform_netns_get (stack[i].pl->platform), stack[i].ns_types); + } + + /* pop some again. */ + for (i = nmtst_get_rand_int () % (nstack + 1); i > 0; i--) { + g_assert (nstack > 0); + nstack--; + nmp_netns_pop (nm_platform_netns_get (stack[nstack].pl->platform)); + } + + for (i = 0; i < G_N_ELEMENTS (ns_types_test); i++) { + int ns_type = ns_types_test[i]; + PlatformData *p; + gs_free char *current_namespace_id = NULL; + + p = pl_base; + for (j = nstack; j >= 1; ) { + j--; + if (NM_FLAGS_HAS (stack[j].ns_types, ns_type)) { + p = stack[j].pl; + break; + } + } + + current_namespace_id = _get_current_namespace_id (ns_type); + + if (ns_type == CLONE_NEWNET) { + g_assert_cmpstr (current_namespace_id, ==, p->ns_net); + for (j = 0; j < G_N_ELEMENTS (pl); j++) { + gs_free char *data = NULL; + + if (p == &pl[j]) + g_assert_cmpint (nmtstp_run_command ("ip link show %s 1>/dev/null", pl[j].device_name), ==, 0); + else + g_assert_cmpint (nmtstp_run_command ("ip link show %s 2>/dev/null", pl[j].device_name), !=, 0); + + data = _get_sysctl_value (pl[j].sysctl_path); + if (p == &pl[j]) + g_assert_cmpstr (data, ==, pl[j].sysctl_value); + else + g_assert (!data); + } + } else if (ns_type == CLONE_NEWNS) { + g_assert_cmpstr (current_namespace_id, ==, p->ns_mnt); + for (j = 0; j < G_N_ELEMENTS (pl); j++) { + char path[600]; + gs_free char *data = NULL; + + nm_sprintf_buf (path, "/sys/devices/virtual/net/%s/ifindex", pl[j].device_name); + + data = _get_sysctl_value (path); + if (p == &pl[j]) + g_assert_cmpstr (data, ==, nm_sprintf_buf (path, "%d", nmtstp_link_get_typed (p->platform, 0, p->device_name, NM_LINK_TYPE_DUMMY)->ifindex)); + else + g_assert (!data); + } + } else + g_assert_not_reached (); + } + + + for (i = nstack; i >= 1; ) { + i--; + nmp_netns_pop (nm_platform_netns_get (stack[i].pl->platform)); + } +} + +/*****************************************************************************/ + +static void +test_netns_bind_to_path (gpointer fixture, gconstpointer test_data) +{ +#define P_VAR_RUN "/var/run" +#define P_VAR_RUN_NETNS "/var/run/netns" +#define P_VAR_RUN_NETNS_BINDNAME "/var/run/netns/"P_NETNS_BINDNAME +#define P_NETNS_BINDNAME "nmtst-iproute2-netns" + gs_unref_object NMPlatform *platform_0 = NULL; + gs_unref_object NMPlatform *platform_1 = NULL; + gs_unref_object NMPlatform *platform_2 = NULL; + nm_auto_pop_netns NMPNetns *netns_pop = NULL; + NMPlatform *platforms[3]; + NMPNetns *netns; + int i; + + if (_test_netns_check_skip ()) + return; + + platforms[0] = platform_0 = g_object_new (NM_TYPE_LINUX_PLATFORM, NM_PLATFORM_NETNS_SUPPORT, TRUE, NULL); + platforms[1] = platform_1 = _test_netns_create_platform (); + platforms[2] = platform_2 = _test_netns_create_platform (); + + i = nmtst_get_rand_int () % 4; + if (i != 3) + g_assert (nm_platform_netns_push (platforms[i], &netns_pop)); + + g_assert_cmpint (mount ("tmpfs", P_VAR_RUN, "tmpfs", MS_NOATIME | MS_NODEV | MS_NOSUID, "mode=0755,size=32K"), ==, 0); + g_assert_cmpint (mkdir (P_VAR_RUN_NETNS, 755), ==, 0); + + i = (nmtst_get_rand_int () % 2) + 1; + netns = nm_platform_netns_get (platforms[i]); + + _ADD_DUMMY (platforms[i], "dummy2b"); + + g_assert (!g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS)); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true 2>/dev/null"), !=, 0); + + g_assert (nmp_netns_bind_to_path (netns, P_VAR_RUN_NETNS_BINDNAME, NULL)); + + g_assert (g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS)); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true"), ==, 0); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" ip link show dummy2b 1>/dev/null"), ==, 0); + + g_assert (nmp_netns_bind_to_path_destroy (netns, P_VAR_RUN_NETNS_BINDNAME)); + + g_assert (!g_file_test (P_VAR_RUN_NETNS_BINDNAME, G_FILE_TEST_EXISTS)); + g_assert_cmpint (nmtstp_run_command ("ip netns exec "P_NETNS_BINDNAME" true 2>/dev/null"), !=, 0); + + g_assert_cmpint (umount (P_VAR_RUN), ==, 0); +} + /*****************************************************************************/ void @@ -1894,5 +2338,10 @@ 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_setup, test_netns_general, _test_netns_teardown); + g_test_add_vtable ("/general/netns/set-netns", 0, NULL, _test_netns_setup, test_netns_set_netns, _test_netns_teardown); + g_test_add_vtable ("/general/netns/push", 0, NULL, _test_netns_setup, test_netns_push, _test_netns_teardown); + g_test_add_vtable ("/general/netns/bind-to-path", 0, NULL, _test_netns_setup, test_netns_bind_to_path, _test_netns_teardown); } } diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 3b44abb8..d77170b3 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -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); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index f5fa024b..85851854 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -314,7 +314,7 @@ test_ip4_zero_gateway (void) nmtstp_run_command_check ("ip route add 1.2.3.2/32 dev %s", DEVICE_NAME); NMTST_WAIT_ASSERT (100, { - nmtstp_wait_for_signal (10); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 10); if ( nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.1"), 32, 0) && nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.2"), 32, 0)) break; @@ -322,7 +322,7 @@ test_ip4_zero_gateway (void) nmtstp_run_command_check ("ip route flush dev %s", DEVICE_NAME); - nmtstp_wait_for_signal (50); + nmtstp_wait_for_signal (NM_PLATFORM_GET, 50); nm_platform_process_events (NM_PLATFORM_GET); } diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c index 029601e4..af285b45 100644 --- a/src/platform/wifi/wifi-utils-wext.c +++ b/src/platform/wifi/wifi-utils-wext.c @@ -101,7 +101,7 @@ wifi_wext_get_mode (WifiData *data) struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) { if (errno != ENODEV) { @@ -118,6 +118,7 @@ wifi_wext_get_mode (WifiData *data) case IW_MODE_MASTER: return NM_802_11_MODE_AP; case IW_MODE_INFRA: + case IW_MODE_AUTO: /* hack for WEXT devices reporting IW_MODE_AUTO */ return NM_802_11_MODE_INFRA; default: break; @@ -150,7 +151,7 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) return FALSE; } - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) { if (errno != ENODEV) { nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting mode %d", @@ -174,7 +175,7 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave) } else wrq.u.power.disabled = 1; - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) { if (errno != ENODEV) { nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT, @@ -193,7 +194,7 @@ wifi_wext_get_freq (WifiData *data) struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) { nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s): error getting frequency: %s", @@ -227,7 +228,7 @@ wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid) struct iwreq wrq; memset (&wrq, 0, sizeof (wrq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) { nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s): error getting associated BSSID: %s", @@ -246,7 +247,7 @@ wifi_wext_get_rate (WifiData *data) int err; memset (&wrq, 0, sizeof (wrq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); err = ioctl (wext->fd, SIOCGIWRATE, &wrq); return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0); } @@ -356,7 +357,7 @@ wifi_wext_get_qual (WifiData *data) wrq.u.data.pointer = &stats; wrq.u.data.length = sizeof (stats); wrq.u.data.flags = 1; /* Clear updated flag */ - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) { nm_log_warn (LOGD_HW | LOGD_WIFI, @@ -393,7 +394,7 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (channel > 0) { wrq.u.freq.flags = IW_FREQ_FIXED; @@ -425,7 +426,7 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) wrq.u.essid.length = len; wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */ - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0) return TRUE; @@ -448,7 +449,7 @@ wext_can_scan (WifiDataWext *wext) struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWSCAN, &wrq) < 0) { if (errno == EOPNOTSUPP) return FALSE; @@ -466,7 +467,7 @@ wext_get_range (WifiDataWext *wext, struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); - strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); wrq.u.data.pointer = (caddr_t) range; wrq.u.data.length = sizeof (struct iw_range); @@ -666,7 +667,7 @@ wifi_wext_is_wifi (const char *iface) fd = socket (PF_INET, SOCK_DGRAM, 0); if (fd >= 0) { - strncpy (iwr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); + nm_utils_ifname_cpy (iwr.ifr_ifrn.ifrn_name, iface); if (ioctl (fd, SIOCGIWNAME, &iwr) == 0) is_wifi = TRUE; close (fd); |