From baf5f633740f002ff17b3e42ea5c48618861bc88 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 25 May 2015 11:23:08 +0200 Subject: [PATCH 01/17] utils: add NM_FLAGS_SET(), NM_FLAGS_UNSET() and NM_FLAGS_ASSIGN() macros (cherry picked from commit 57958b93b62a29053ca0f7d4e2b2844a50627d21) --- include/nm-macros-internal.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/nm-macros-internal.h b/include/nm-macros-internal.h index 8260c2b562..9be6b0f321 100644 --- a/include/nm-macros-internal.h +++ b/include/nm-macros-internal.h @@ -189,6 +189,29 @@ nm_clear_g_source (guint *id) #define NM_FLAGS_ANY(flags, check) ( ( ((flags) & (check)) != 0 ) ? TRUE : FALSE ) #define NM_FLAGS_ALL(flags, check) ( ( ((flags) & (check)) == (check) ) ? TRUE : FALSE ) +#define NM_FLAGS_SET(flags, val) ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + _flags | _val; \ + }) + +#define NM_FLAGS_UNSET(flags, val) ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + _flags & (~_val); \ + }) + +#define NM_FLAGS_ASSIGN(flags, val, assign) ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + (assign) \ + ? _flags | (_val) \ + : _flags & (~_val); \ + }) + /*****************************************************************************/ #endif /* __NM_MACROS_INTERNAL_H__ */ From 90eb13a111b958dcfb633c5dcb2beb39592ff175 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 18 May 2015 17:37:05 +0200 Subject: [PATCH 02/17] core: add option to suppress error logging if nm_utils_modprobe() fails We don't want error logging for nm_platform_link_add() which tries to load the bonding module. Later we will run tests as non-root, where modprobe will fail. Logging an error would break the tests. (cherry picked from commit 39f2b51abb70100f62c42b77e55cf3e386b9c49a) --- src/NetworkManagerUtils.c | 23 +++++++++++++++++++---- src/NetworkManagerUtils.h | 2 +- src/devices/nm-device.c | 2 +- src/platform/nm-linux-platform.c | 2 +- src/ppp-manager/nm-ppp-manager.c | 2 +- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index a989813d47..2225541c8d 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -176,8 +176,19 @@ nm_spawn_process (const char *args, GError **error) return status; } +static const char * +_trunk_first_line (char *str) +{ + char *s; + + s = strchr (str, '\n'); + if (s) + s[0] = '\0'; + return str; +} + int -nm_utils_modprobe (GError **error, const char *arg1, ...) +nm_utils_modprobe (GError **error, gboolean suppress_error_logging, const char *arg1, ...) { gs_unref_ptrarray GPtrArray *argv = NULL; int exit_status; @@ -185,6 +196,8 @@ nm_utils_modprobe (GError **error, const char *arg1, ...) #define ARGV_TO_STR(argv) (_log_str ? _log_str : (_log_str = g_strjoinv (" ", (char **) argv->pdata))) GError *local = NULL; va_list ap; + NMLogLevel llevel = suppress_error_logging ? LOGL_DEBUG : LOGL_ERR; + gs_free char *std_out = NULL, *std_err = NULL; g_return_val_if_fail (!error || !*error, -1); g_return_val_if_fail (arg1, -1); @@ -202,12 +215,14 @@ nm_utils_modprobe (GError **error, const char *arg1, ...) g_ptr_array_add (argv, NULL); nm_log_dbg (LOGD_CORE, "modprobe: '%s'", ARGV_TO_STR (argv)); - if (!g_spawn_sync (NULL, (char **) argv->pdata, NULL, 0, NULL, NULL, NULL, NULL, &exit_status, &local)) { - nm_log_err (LOGD_CORE, "modprobe: '%s' failed: %s", ARGV_TO_STR (argv), local->message); + if (!g_spawn_sync (NULL, (char **) argv->pdata, NULL, 0, NULL, NULL, &std_out, &std_err, &exit_status, &local)) { + nm_log (llevel, LOGD_CORE, "modprobe: '%s' failed: %s", ARGV_TO_STR (argv), local->message); g_propagate_error (error, local); return -1; } else if (exit_status != 0) - nm_log_err (LOGD_CORE, "modprobe: '%s' exited with error %d", ARGV_TO_STR (argv), exit_status); + nm_log (llevel, LOGD_CORE, "modprobe: '%s' exited with error %d%s%s%s%s%s%s", ARGV_TO_STR (argv), exit_status, + std_out&&*std_out ? " (" : "", std_out&&*std_out ? _trunk_first_line (std_out) : "", std_out&&*std_out ? ")" : "", + std_err&&*std_err ? " (" : "", std_err&&*std_err ? _trunk_first_line (std_err) : "", std_err&&*std_err ? ")" : ""); return exit_status; } diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 10f1f12f63..ad584e2297 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -51,7 +51,7 @@ nm_utils_ip6_route_metric_normalize (guint32 metric) int nm_spawn_process (const char *args, GError **error); -int nm_utils_modprobe (GError **error, const char *arg1, ...) G_GNUC_NULL_TERMINATED; +int nm_utils_modprobe (GError **error, gboolean suppress_error_loggin, const char *arg1, ...) G_GNUC_NULL_TERMINATED; /** * str_if_set: diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 3d5cda21b9..5ea53a749e 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5216,7 +5216,7 @@ share_init (void) } for (iter = modules; *iter; iter++) - nm_utils_modprobe (NULL, *iter, NULL); + nm_utils_modprobe (NULL, FALSE, *iter, NULL); return TRUE; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index b97237d96c..1521798831 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2439,7 +2439,7 @@ link_add (NMPlatform *platform, * bond0 automatically. */ if (!g_file_test ("/sys/class/net/bonding_masters", G_FILE_TEST_EXISTS)) - nm_utils_modprobe (NULL, "bonding", "max_bonds=0", NULL); + nm_utils_modprobe (NULL, TRUE, "bonding", "max_bonds=0", NULL); } debug ("link: add link '%s' of type '%s' (%d)", diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c index 791296590b..414b16c91c 100644 --- a/src/ppp-manager/nm-ppp-manager.c +++ b/src/ppp-manager/nm-ppp-manager.c @@ -1106,7 +1106,7 @@ nm_ppp_manager_start (NMPPPManager *manager, /* Make sure /dev/ppp exists (bgo #533064) */ if (stat ("/dev/ppp", &st) || !S_ISCHR (st.st_mode)) - nm_utils_modprobe (NULL, "ppp_generic", NULL); + nm_utils_modprobe (NULL, FALSE, "ppp_generic", NULL); connection = nm_act_request_get_connection (req); g_assert (connection); From a030ac36d3ddffb8b1c3b51343123fdeae47548b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 15 May 2015 11:46:43 +0200 Subject: [PATCH 03/17] tests: allow running the link test without a writeable sysfs This fixes the test run in a container/our NETNS/NEWUSER test jail. (cherry picked from commit f9dd7f0d849d277cf224c10d069d689764cd2973) --- src/platform/tests/test-common.c | 24 ++++++++++++----- src/platform/tests/test-common.h | 1 + src/platform/tests/test-link.c | 44 ++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 2eda47cc8b..203a6e18b1 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -19,6 +19,13 @@ nmtst_platform_is_root_test () NM_PRAGMA_WARNING_REENABLE } +gboolean +nmtst_platform_is_sysfs_writable () +{ + return !nmtst_platform_is_root_test () + || (access ("/sys/devices", W_OK) == 0); +} + SignalData * add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname) { @@ -325,12 +332,17 @@ main (int argc, char **argv) g_error ("mount(\"/sys/devices\") failed with %s (%d)", strerror (errsv), errsv); } if (mount (NULL, "/sys/devices", "sysfs", MS_REMOUNT, NULL) != 0) { - errsv = errno; - g_error ("remount(\"/sys/devices\") failed with %s (%d)", strerror (errsv), errsv); - } - if (mount ("/sys/devices/devices", "/sys/devices", "sysfs", MS_BIND, NULL) != 0) { - errsv = errno; - g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv); + /* Read-write remount failed. Never mind, we're probably just a root in + * our user NS. */ + if (umount ("/sys/devices") != 0) { + errsv = errno; + g_error ("umount(\"/sys/devices\") failed with %s (%d)", strerror (errsv), errsv); + } + } else { + if (mount ("/sys/devices/devices", "/sys/devices", "sysfs", MS_BIND, NULL) != 0) { + errsv = errno; + g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv); + } } } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 56e27f6581..563d9fb4f6 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -29,6 +29,7 @@ typedef struct { } SignalData; gboolean nmtst_platform_is_root_test (void); +gboolean nmtst_platform_is_sysfs_writable (void); SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname); #define add_signal(name, change_type, callback) add_signal_full (name, change_type, (GCallback) callback, 0, NULL) diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index bbd42946af..102fe795f7 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -219,12 +219,14 @@ test_slave (int master, int type, SignalData *master_changed) /* Set slave option */ switch (type) { case NM_LINK_TYPE_BRIDGE: - g_assert (nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789")); - no_error (); - value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, "priority"); - no_error (); - g_assert_cmpstr (value, ==, "789"); - g_free (value); + if (nmtst_platform_is_sysfs_writable ()) { + g_assert (nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789")); + no_error (); + value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, "priority"); + no_error (); + g_assert_cmpstr (value, ==, "789"); + g_free (value); + } break; default: break; @@ -294,21 +296,25 @@ test_software (NMLinkType link_type, const char *link_typename) /* Set master option */ switch (link_type) { case NM_LINK_TYPE_BRIDGE: - g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789")); - no_error (); - value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay"); - no_error (); - g_assert_cmpstr (value, ==, "789"); - g_free (value); + if (nmtst_platform_is_sysfs_writable ()) { + g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789")); + no_error (); + value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay"); + no_error (); + g_assert_cmpstr (value, ==, "789"); + g_free (value); + } break; case NM_LINK_TYPE_BOND: - g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup")); - no_error (); - value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "mode"); - no_error (); - /* When reading back, the output looks slightly different. */ - g_assert (g_str_has_prefix (value, "active-backup")); - g_free (value); + if (nmtst_platform_is_sysfs_writable ()) { + g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup")); + no_error (); + value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "mode"); + no_error (); + /* When reading back, the output looks slightly different. */ + g_assert (g_str_has_prefix (value, "active-backup")); + g_free (value); + } break; default: break; From cf0a0ed576819f8f984917267f1bb2c1b2bea0e1 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 15 May 2015 11:45:24 +0200 Subject: [PATCH 04/17] tests: use a user ns to fake root (cherry picked from commit ed01c975d8407f2777d17a156751cfc9fdfae797) --- src/platform/tests/test-common.c | 58 ++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 203a6e18b1..6170e403eb 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -285,6 +285,46 @@ run_command (const char *format, ...) NMTST_DEFINE(); +static gboolean +unshare_user () +{ + FILE *f; + uid_t uid = geteuid (); + gid_t gid = getegid (); + + /* Already a root? */ + if (gid == 0 && uid == 0) + return TRUE; + + /* Become a root in new user NS. */ + if (unshare (CLONE_NEWUSER) != 0) + return FALSE; + + /* Since Linux 3.19 we have to disable setgroups() in order to map users. + * Just proceed if the file is not there. */ + f = fopen ("/proc/self/setgroups", "w"); + if (f) { + fprintf (f, "deny"); + fclose (f); + } + + /* Map current UID to root in NS to be created. */ + f = fopen ("/proc/self/uid_map", "w"); + if (!f) + return FALSE; + fprintf (f, "0 %d 1", uid); + fclose (f); + + /* Map current GID to root in NS to be created. */ + f = fopen ("/proc/self/gid_map", "w"); + if (!f) + return FALSE; + fprintf (f, "0 %d 1", gid); + fclose (f); + + return TRUE; +} + int main (int argc, char **argv) { @@ -293,17 +333,21 @@ main (int argc, char **argv) init_tests (&argc, &argv); - if (nmtst_platform_is_root_test () && getuid() != 0) { - /* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */ - nmtst_reexec_sudo (); + if ( nmtst_platform_is_root_test () + && (geteuid () != 0 || getegid () != 0)) { + if ( g_getenv ("NMTST_FORCE_REAL_ROOT") + || !unshare_user ()) { + /* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */ + nmtst_reexec_sudo (); #ifdef REQUIRE_ROOT_TESTS - g_print ("Fail test: requires root privileges (%s)\n", program); - return EXIT_FAILURE; + g_print ("Fail test: requires root privileges (%s)\n", program); + return EXIT_FAILURE; #else - g_print ("Skipping test: requires root privileges (%s)\n", program); - return g_test_run (); + g_print ("Skipping test: requires root privileges (%s)\n", program); + return g_test_run (); #endif + } } if (nmtst_platform_is_root_test () && !g_getenv ("NMTST_NO_UNSHARE")) { From acb39d4b3190968d6f84bd229ac67325be479eff Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 4 May 2015 15:55:12 +0200 Subject: [PATCH 05/17] platform: merge setup_devices() function into constructed() We already populate the netlink cache in constructed(). No need to wait with udev devices until nm_platform_query_devices(). Just do it right away. Add a hack to keep 'lo' default-unmanaged. Now that we load udev devices earlier, we end up clearing the default-unmanged flag on 'lo', which has bad consequences. (cherry picked from commit d6ce01f115e0195da08e0b1c0cde1c25ea747f77) --- src/devices/nm-device.c | 9 ++++++++- src/platform/nm-linux-platform.c | 16 ++++------------ src/platform/nm-platform.c | 4 ---- src/platform/nm-platform.h | 2 -- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5ea53a749e..625ad3ee33 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1096,7 +1096,14 @@ nm_device_finish_init (NMDevice *self) nm_device_enslave_slave (priv->master, self, NULL); if (priv->ifindex > 0) { - if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) { + if (priv->ifindex == 1) { + /* keep 'lo' as default-unmanaged. */ + + /* FIXME: either find a better way to unmange 'lo' that cannot be changed + * by user configuration (NM_UNMANGED_LOOPBACK?) or fix managing 'lo'. + * Currently it can happen that NM deletes 127.0.0.1 address. */ + nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, TRUE); + } else if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) { nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged); nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, platform_unmanaged); } else { diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1521798831..c2147a2b94 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4775,6 +4775,8 @@ constructed (GObject *_object) int channel_flags; gboolean status; int nle; + GUdevEnumerator *enumerator; + GList *devices, *iter; /* Initialize netlink socket for requests */ priv->nlh = setup_socket (FALSE, platform); @@ -4839,16 +4841,6 @@ constructed (GObject *_object) priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit); - G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object); -} - -static void -setup_devices (NMPlatform *platform) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - GUdevEnumerator *enumerator; - GList *devices, *iter; - /* And read initial device list */ enumerator = g_udev_enumerator_new (priv->udev_client); g_udev_enumerator_add_match_subsystem (enumerator, "net"); @@ -4862,6 +4854,8 @@ setup_devices (NMPlatform *platform) } g_list_free (devices); g_object_unref (enumerator); + + G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object); } static void @@ -4899,8 +4893,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) object_class->constructed = constructed; object_class->finalize = nm_linux_platform_finalize; - platform_class->setup_devices = setup_devices; - platform_class->sysctl_set = sysctl_set; platform_class->sysctl_get = sysctl_get; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 876237e9ca..97e0295fc2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -407,10 +407,6 @@ nm_platform_query_devices (NMPlatform *self) NM_PLATFORM_REASON_INTERNAL); } g_array_unref (links_array); - - /* Platform specific device setup. */ - if (klass->setup_devices) - klass->setup_devices (self); } /** diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index ef1deff9ca..e9184a0148 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -368,8 +368,6 @@ struct _NMPlatform { typedef struct { GObjectClass parent; - void (*setup_devices) (NMPlatform *); - gboolean (*sysctl_set) (NMPlatform *, const char *path, const char *value); char * (*sysctl_get) (NMPlatform *, const char *path); From 4e0af0aa52922090058f2f92acc277a2bf4e072f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 4 May 2015 16:54:51 +0200 Subject: [PATCH 06/17] platform: move nm_platform_query_devices() to nm-manager nm_platform_query_devices() would raise an 'added' signal for all its links. That is bad style because it could confuse other listeners for platform signals which don't expect such artificial change signals. The public API of NMPlatform already gives NMManager the ability to 'pull' all the links and iterate them itself. Before, nm_platform_query_devices() would also initialize udev devices, so there was a more compelling reason for this function. (cherry picked from commit d7a312d17a09b748d5aa06d7dfbebc66f0e8cf68) --- src/nm-manager.c | 17 ++++++++++++++++- src/platform/nm-platform.c | 26 -------------------------- src/platform/nm-platform.h | 2 -- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 4950c98f86..0c1201cee2 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1977,6 +1977,21 @@ platform_link_cb (NMPlatform *platform, } } +static void +platform_query_devices (NMManager *self) +{ + GArray *links_array; + NMPlatformLink *links; + int i; + + links_array = nm_platform_link_get_all (NM_PLATFORM_GET); + links = (NMPlatformLink *) links_array->data; + for (i = 0; i < links_array->len; i++) + platform_link_added (self, links[i].ifindex, &links[i], NM_PLATFORM_REASON_INTERNAL); + + g_array_unref (links_array); +} + static void rfkill_manager_rfkill_changed_cb (NMRfkillManager *rfkill_mgr, RfKillType rtype, @@ -4113,7 +4128,7 @@ nm_manager_start (NMManager *self) /* Start device factories */ nm_device_factory_manager_for_each_factory (start_factory, NULL); - nm_platform_query_devices (NM_PLATFORM_GET); + platform_query_devices (self); /* * Connections added before the manager is started do not emit diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 97e0295fc2..79e83b6aef 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -383,32 +383,6 @@ nm_platform_sysctl_get_int_checked (NMPlatform *self, const char *path, guint ba /******************************************************************/ -/** - * nm_platform_query_devices: - * self: platform instance - * - * Emit #NMPlatform:link-changed ADDED signals for all currently-known links. - * Should only be called at startup. - */ -void -nm_platform_query_devices (NMPlatform *self) -{ - GArray *links_array; - NMPlatformLink *links; - int i; - - _CHECK_SELF_VOID (self, klass); - - links_array = nm_platform_link_get_all (self); - links = (NMPlatformLink *) links_array->data; - for (i = 0; i < links_array->len; i++) { - g_signal_emit (self, signals[SIGNAL_LINK_CHANGED], 0, - links[i].ifindex, &links[i], NM_PLATFORM_SIGNAL_ADDED, - NM_PLATFORM_REASON_INTERNAL); - } - g_array_unref (links_array); -} - /** * nm_platform_link_get_all: * self: platform instance diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index e9184a0148..5b42968733 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -532,8 +532,6 @@ void nm_platform_set_error (NMPlatform *self, NMPlatformError error); NMPlatformError nm_platform_get_error (NMPlatform *self); const char *nm_platform_get_error_msg (NMPlatform *self); -void nm_platform_query_devices (NMPlatform *self); - gboolean nm_platform_sysctl_set (NMPlatform *self, const char *path, const char *value); char *nm_platform_sysctl_get (NMPlatform *self, const char *path); gint32 nm_platform_sysctl_get_int32 (NMPlatform *self, const char *path, gint32 fallback); From cd2d241fb7b51b4685a9043c6b7315eeedd78039 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 14 Apr 2015 22:34:01 +0200 Subject: [PATCH 07/17] platform: add nm-platform-utils.[ch] files There is no general purpose file for platform utilities. We only have nm-platform.h, which contains (mostly) functions that operate on a NMPlatform instance (and that can be mocked using NMFakePlatform). Add a new file for independent utility functions. nm-platform-utils.c should not call into functions having a NMPlatform instance, to have them independent from platform caching and the platform singleton. (cherry picked from commit ce700d94f54eae64d0f3aac0c6ef50a051dd9a2b) --- src/Makefile.am | 4 ++++ src/platform/nm-platform-utils.c | 23 +++++++++++++++++++ src/platform/nm-platform-utils.h | 29 +++++++++++++++++++++++ src/platform/tests/.gitignore | 9 ++++---- src/platform/tests/Makefile.am | 8 +++++++ src/platform/tests/test-general.c | 38 +++++++++++++++++++++++++++++++ 6 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/platform/nm-platform-utils.c create mode 100644 src/platform/nm-platform-utils.h create mode 100644 src/platform/tests/test-general.c diff --git a/src/Makefile.am b/src/Makefile.am index 90ee90d492..b9809a28a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -220,6 +220,8 @@ nm_sources = \ platform/nm-linux-platform.h \ platform/nm-platform.c \ platform/nm-platform.h \ + platform/nm-platform-utils.c \ + platform/nm-platform-utils.h \ platform/wifi/wifi-utils-nl80211.c \ platform/wifi/wifi-utils-nl80211.h \ platform/wifi/wifi-utils-private.h \ @@ -477,6 +479,8 @@ libnm_iface_helper_la_SOURCES = \ platform/nm-linux-platform.h \ platform/nm-platform.c \ platform/nm-platform.h \ + platform/nm-platform-utils.c \ + platform/nm-platform-utils.h \ platform/wifi/wifi-utils-nl80211.c \ platform/wifi/wifi-utils-nl80211.h \ platform/wifi/wifi-utils-private.h \ diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c new file mode 100644 index 0000000000..34d4b0a69a --- /dev/null +++ b/src/platform/nm-platform-utils.c @@ -0,0 +1,23 @@ +/* -*- 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) 2015 Red Hat, Inc. + */ + +#include "nm-platform-utils.h" + + diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h new file mode 100644 index 0000000000..a6da1a8934 --- /dev/null +++ b/src/platform/nm-platform-utils.h @@ -0,0 +1,29 @@ +/* -*- 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) 2015 Red Hat, Inc. + */ + +#ifndef __NM_PLATFORM_UTILS_H__ +#define __NM_PLATFORM_UTILS_H__ + +#include "config.h" + +#include "nm-platform.h" + + +#endif /* __NM_PLATFORM_UTILS_H__ */ diff --git a/src/platform/tests/.gitignore b/src/platform/tests/.gitignore index 5457fbca6c..cdd8a51f83 100644 --- a/src/platform/tests/.gitignore +++ b/src/platform/tests/.gitignore @@ -1,11 +1,12 @@ /dump /monitor /platform -/test-link-fake -/test-link-linux /test-address-fake /test-address-linux +/test-cleanup-fake +/test-cleanup-linux +/test-general +/test-link-fake +/test-link-linux /test-route-fake /test-route-linux -/test-cleanup-fake -/test-cleanup-linux \ No newline at end of file diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am index 92400f9091..76b40f7ca3 100644 --- a/src/platform/tests/Makefile.am +++ b/src/platform/tests/Makefile.am @@ -37,6 +37,7 @@ noinst_PROGRAMS = \ test-link-linux \ test-address-fake \ test-address-linux \ + test-general \ test-route-fake \ test-route-linux \ test-cleanup-fake \ @@ -109,12 +110,19 @@ test_cleanup_linux_CPPFLAGS = \ -DKERNEL_HACKS=1 test_cleanup_linux_LDADD = $(PLATFORM_LDADD) +test_general_SOURCES = \ + test-general.c +test_general_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + + @VALGRIND_RULES@ TESTS = \ test-address-fake \ test-address-linux \ test-cleanup-fake \ test-cleanup-linux \ + test-general \ test-link-fake \ test-link-linux \ test-route-fake \ diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c new file mode 100644 index 0000000000..2f29d7de70 --- /dev/null +++ b/src/platform/tests/test-general.c @@ -0,0 +1,38 @@ +/* -*- 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) 2015 Red Hat, Inc. + */ + +#include "nm-platform-utils.h" + +#include "nm-logging.h" + +#include "nm-test-utils.h" + + +/******************************************************************/ + +NMTST_DEFINE (); + +int +main (int argc, char **argv) +{ + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + + return g_test_run (); +} From 716dd795de3c05f825a1bdb2e1f7a7d7a0677aa2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 2 May 2015 07:59:59 +0200 Subject: [PATCH 08/17] platform: move code udev_get_driver() to nmp_utils_udev_get_driver() (cherry picked from commit 77a3767d1e7f99a4f59d292eeab9363687697606) --- src/platform/nm-linux-platform.c | 44 ++------------------------------ src/platform/nm-platform-utils.c | 41 +++++++++++++++++++++++++++++ src/platform/nm-platform-utils.h | 5 ++++ 3 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index c2147a2b94..a991c8648e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -58,6 +58,7 @@ #include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-linux-platform.h" +#include "nm-platform-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-logging.h" @@ -479,47 +480,6 @@ ethtool_get_permanent_address (const char *ifname, return TRUE; } -/****************************************************************** - * udev - ******************************************************************/ - -static const char * -udev_get_driver (GUdevDevice *device, int ifindex) -{ - GUdevDevice *parent = NULL, *grandparent = NULL; - const char *driver, *subsys; - - driver = g_udev_device_get_driver (device); - if (driver) - goto out; - - /* Try the parent */ - parent = g_udev_device_get_parent (device); - if (parent) { - driver = g_udev_device_get_driver (parent); - if (!driver) { - /* Try the grandparent if it's an ibmebus device or if the - * subsys is NULL which usually indicates some sort of - * platform device like a 'gadget' net interface. - */ - subsys = g_udev_device_get_subsystem (parent); - if ( (g_strcmp0 (subsys, "ibmebus") == 0) - || (subsys == NULL)) { - grandparent = g_udev_device_get_parent (parent); - if (grandparent) - driver = g_udev_device_get_driver (grandparent); - } - } - } - g_clear_object (&parent); - g_clear_object (&grandparent); - -out: - /* Intern the string so we don't have to worry about memory - * management in NMPlatformLink. */ - return g_intern_string (driver); -} - /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -1102,7 +1062,7 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin udev_device = g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (info->ifindex)); if (udev_device) { - info->driver = udev_get_driver (udev_device, info->ifindex); + info->driver = nmp_utils_udev_get_driver (udev_device); info->udi = g_udev_device_get_sysfs_path (udev_device); info->initialized = TRUE; } diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 34d4b0a69a..62127142cb 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -20,4 +20,45 @@ #include "nm-platform-utils.h" +/****************************************************************** + * udev + ******************************************************************/ + +const char * +nmp_utils_udev_get_driver (GUdevDevice *device) +{ + GUdevDevice *parent = NULL, *grandparent = NULL; + const char *driver, *subsys; + + driver = g_udev_device_get_driver (device); + if (driver) + goto out; + + /* Try the parent */ + parent = g_udev_device_get_parent (device); + if (parent) { + driver = g_udev_device_get_driver (parent); + if (!driver) { + /* Try the grandparent if it's an ibmebus device or if the + * subsys is NULL which usually indicates some sort of + * platform device like a 'gadget' net interface. + */ + subsys = g_udev_device_get_subsystem (parent); + if ( (g_strcmp0 (subsys, "ibmebus") == 0) + || (subsys == NULL)) { + grandparent = g_udev_device_get_parent (parent); + if (grandparent) + driver = g_udev_device_get_driver (grandparent); + } + } + } + g_clear_object (&parent); + g_clear_object (&grandparent); + +out: + /* Intern the string so we don't have to worry about memory + * management in NMPlatformLink. */ + return g_intern_string (driver); +} + diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index a6da1a8934..76f285d7d0 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -23,7 +23,12 @@ #include "config.h" +#include + #include "nm-platform.h" +const char *nmp_utils_udev_get_driver (GUdevDevice *device); + + #endif /* __NM_PLATFORM_UTILS_H__ */ From a72350c4da4a13cb1103e989110115ba5d61b225 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 3 May 2015 10:02:29 +0200 Subject: [PATCH 09/17] platform/trivial: move ethtool_supports_carrier_detect() code (cherry picked from commit 2b8f3331d76497433b761bfa1c15640de28692f5) --- src/platform/nm-linux-platform.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a991c8648e..1b83765de0 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -480,6 +480,18 @@ ethtool_get_permanent_address (const char *ifname, return TRUE; } +static gboolean +ethtool_supports_carrier_detect (const char *ifname) +{ + struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK }; + + /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we + * assume the device supports carrier-detect, otherwise we assume it + * doesn't. + */ + return ethtool_get (ifname, &edata); +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -2701,18 +2713,6 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable return FALSE; } -static gboolean -supports_ethtool_carrier_detect (const char *ifname) -{ - struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK }; - - /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we - * assume the device supports carrier-detect, otherwise we assume it - * doesn't. - */ - return ethtool_get (ifname, &edata); -} - static gboolean supports_mii_carrier_detect (const char *ifname) { @@ -2765,7 +2765,7 @@ link_supports_carrier_detect (NMPlatform *platform, int ifindex) * us whether the device actually supports carrier detection in the first * place. We assume any device that does implements one of these two APIs. */ - return supports_ethtool_carrier_detect (name) || supports_mii_carrier_detect (name); + return ethtool_supports_carrier_detect (name) || supports_mii_carrier_detect (name); } static gboolean From 6c768011904778c541e0eb9a8104f8089189cf71 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 3 May 2015 10:06:27 +0200 Subject: [PATCH 10/17] platform: factor out ethtool_supports_vlans() function (cherry picked from commit 4be9394864f7df42c64048f01a00484047fadb4f) --- src/platform/nm-linux-platform.c | 54 ++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1b83765de0..ecdf3b8ce0 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -492,6 +492,35 @@ ethtool_supports_carrier_detect (const char *ifname) return ethtool_get (ifname, &edata); } +static gboolean +ethtool_supports_vlans (const char *ifname) +{ + gs_free struct ethtool_gfeatures *features = NULL; + int idx, block, bit, size; + + if (!ifname) + return FALSE; + + idx = ethtool_get_stringset_index (ifname, ETH_SS_FEATURES, "vlan-challenged"); + if (idx == -1) { + debug ("vlan-challenged ethtool feature does not exist?"); + return FALSE; + } + + block = idx / 32; + bit = idx % 32; + size = block + 1; + + features = g_malloc0 (sizeof (*features) + size * sizeof (struct ethtool_get_features_block)); + features->cmd = ETHTOOL_GFEATURES; + features->size = size; + + if (!ethtool_get (ifname, features)) + return FALSE; + + return !(features->features[block].active & (1 << bit)); +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -2772,35 +2801,12 @@ static gboolean link_supports_vlans (NMPlatform *platform, int ifindex) { auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); - const char *name = nm_platform_link_get_name (platform, ifindex); - gs_free struct ethtool_gfeatures *features = NULL; - int idx, block, bit, size; /* Only ARPHRD_ETHER links can possibly support VLANs. */ if (!rtnllink || rtnl_link_get_arptype (rtnllink) != ARPHRD_ETHER) return FALSE; - if (!name) - return FALSE; - - idx = ethtool_get_stringset_index (name, ETH_SS_FEATURES, "vlan-challenged"); - if (idx == -1) { - debug ("vlan-challenged ethtool feature does not exist?"); - return FALSE; - } - - block = idx / 32; - bit = idx % 32; - size = block + 1; - - features = g_malloc0 (sizeof (*features) + size * sizeof (struct ethtool_get_features_block)); - features->cmd = ETHTOOL_GFEATURES; - features->size = size; - - if (!ethtool_get (name, features)) - return FALSE; - - return !(features->features[block].active & (1 << bit)); + return ethtool_supports_vlans (rtnl_link_get_name (rtnllink)); } static gboolean From 345b73fa1b98541b17092d5be9cc74408e44eb83 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 3 May 2015 10:11:31 +0200 Subject: [PATCH 11/17] platform: factor out ethtool_get_peer_ifindex() function (cherry picked from commit ba084b5b9035075c09ddf8676c8de27df5e0f53a) --- src/platform/nm-linux-platform.c | 41 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index ecdf3b8ce0..a7f925471f 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -521,6 +521,30 @@ ethtool_supports_vlans (const char *ifname) return !(features->features[block].active & (1 << bit)); } +static int +ethtool_get_peer_ifindex (const char *ifname) +{ + gs_free struct ethtool_stats *stats = NULL; + int peer_ifindex_stat; + + if (!ifname) + return 0; + + peer_ifindex_stat = ethtool_get_stringset_index (ifname, ETH_SS_STATS, "peer_ifindex"); + if (peer_ifindex_stat == -1) { + debug ("%s: peer_ifindex ethtool stat does not exist?", ifname); + return FALSE; + } + + stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64)); + stats->cmd = ETHTOOL_GSTATS; + stats->n_stats = peer_ifindex_stat + 1; + if (!ethtool_get (ifname, stats)) + return 0; + + return stats->data[peer_ifindex_stat]; +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -3254,26 +3278,17 @@ static gboolean veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props) { const char *ifname; - gs_free struct ethtool_stats *stats = NULL; - int peer_ifindex_stat; + int peer_ifindex; ifname = nm_platform_link_get_name (platform, ifindex); if (!ifname) return FALSE; - peer_ifindex_stat = ethtool_get_stringset_index (ifname, ETH_SS_STATS, "peer_ifindex"); - if (peer_ifindex_stat == -1) { - debug ("%s: peer_ifindex ethtool stat does not exist?", ifname); - return FALSE; - } - - stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64)); - stats->cmd = ETHTOOL_GSTATS; - stats->n_stats = peer_ifindex_stat + 1; - if (!ethtool_get (ifname, stats)) + peer_ifindex = ethtool_get_peer_ifindex (ifname); + if (peer_ifindex <= 0) return FALSE; - props->peer = stats->data[peer_ifindex_stat]; + props->peer = peer_ifindex; return TRUE; } From ddd9884bcf3f7cb7086f40473172f5521d3164d7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 3 May 2015 10:15:57 +0200 Subject: [PATCH 12/17] platform: factor out ethtool_get_wake_on_lan() function (cherry picked from commit 398819c3ac348abb451f4f6ae15e306328a77ec6) --- src/platform/nm-linux-platform.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a7f925471f..d919b26f62 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -545,6 +545,22 @@ ethtool_get_peer_ifindex (const char *ifname) return stats->data[peer_ifindex_stat]; } +static gboolean +ethtool_get_wake_on_lan (const char *ifname) +{ + struct ethtool_wolinfo wol; + + if (!ifname) + return FALSE; + + memset (&wol, 0, sizeof (wol)); + wol.cmd = ETHTOOL_GWOL; + if (!ethtool_get (ifname, &wol)) + return FALSE; + + return wol.wolopts != 0; +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -3787,16 +3803,9 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) { NMLinkType type = link_get_type (platform, ifindex); - if (type == NM_LINK_TYPE_ETHERNET) { - struct ethtool_wolinfo wol; - - memset (&wol, 0, sizeof (wol)); - wol.cmd = ETHTOOL_GWOL; - if (!ethtool_get (link_get_name (platform, ifindex), &wol)) - return FALSE; - - return wol.wolopts != 0; - } else if (type == NM_LINK_TYPE_WIFI) { + if (type == NM_LINK_TYPE_ETHERNET) + return ethtool_get_wake_on_lan (link_get_name (platform, ifindex)); + else if (type == NM_LINK_TYPE_WIFI) { WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); if (!wifi_data) From 8ad91fa6d0a24785645fb66e5928264ab6806fe4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 2 May 2015 07:59:59 +0200 Subject: [PATCH 13/17] platform: move ethtool_*() to nmp_utils_ethtool_*() (cherry picked from commit ac84b22fc729a291929b0dbc92eed1c97515f4fb) --- src/platform/nm-linux-platform.c | 221 ++----------------------------- src/platform/nm-platform-utils.c | 211 +++++++++++++++++++++++++++++ src/platform/nm-platform-utils.h | 16 +++ 3 files changed, 238 insertions(+), 210 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index d919b26f62..735a0b8834 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -363,204 +362,6 @@ _support_user_ipv6ll_detect (const struct rtnl_link *rtnl_link) #endif } -/****************************************************************** - * ethtool - ******************************************************************/ - -static gboolean -ethtool_get (const char *name, gpointer edata) -{ - struct ifreq ifr; - int fd; - - if (!name || !*name) - return FALSE; - - memset (&ifr, 0, sizeof (ifr)); - strncpy (ifr.ifr_name, name, IFNAMSIZ); - ifr.ifr_data = edata; - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - error ("ethtool: Could not open socket."); - return FALSE; - } - - if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { - debug ("ethtool: Request failed: %s", strerror (errno)); - close (fd); - return FALSE; - } - - close (fd); - return TRUE; -} - -static int -ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *string) -{ - gs_free struct ethtool_sset_info *info = NULL; - gs_free struct ethtool_gstrings *strings = NULL; - guint32 len, i; - - info = g_malloc0 (sizeof (*info) + sizeof (guint32)); - info->cmd = ETHTOOL_GSSET_INFO; - info->reserved = 0; - info->sset_mask = 1ULL << stringset_id; - - if (!ethtool_get (ifname, info)) - return -1; - if (!info->sset_mask) - return -1; - - len = info->data[0]; - - strings = g_malloc0 (sizeof (*strings) + len * ETH_GSTRING_LEN); - strings->cmd = ETHTOOL_GSTRINGS; - strings->string_set = stringset_id; - strings->len = len; - if (!ethtool_get (ifname, strings)) - return -1; - - for (i = 0; i < len; i++) { - if (!strcmp ((char *) &strings->data[i * ETH_GSTRING_LEN], string)) - return i; - } - - return -1; -} - -static gboolean -ethtool_get_driver_info (const char *ifname, - char **out_driver_name, - char **out_driver_version, - char **out_fw_version) -{ - struct ethtool_drvinfo drvinfo = { 0 }; - - if (!ifname) - return FALSE; - - drvinfo.cmd = ETHTOOL_GDRVINFO; - if (!ethtool_get (ifname, &drvinfo)) - return FALSE; - - if (out_driver_name) - *out_driver_name = g_strdup (drvinfo.driver); - if (out_driver_version) - *out_driver_version = g_strdup (drvinfo.version); - if (out_fw_version) - *out_fw_version = g_strdup (drvinfo.fw_version); - - return TRUE; -} - -static gboolean -ethtool_get_permanent_address (const char *ifname, - guint8 *buf, - size_t *length) -{ - gs_free struct ethtool_perm_addr *epaddr = NULL; - - if (!ifname) - return FALSE; - - epaddr = g_malloc0 (sizeof (*epaddr) + NM_UTILS_HWADDR_LEN_MAX); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = NM_UTILS_HWADDR_LEN_MAX; - - if (!ethtool_get (ifname, epaddr)) - return FALSE; - if (!nm_ethernet_address_is_valid (epaddr->data, epaddr->size)) - return FALSE; - - g_assert (epaddr->size <= NM_UTILS_HWADDR_LEN_MAX); - memcpy (buf, epaddr->data, epaddr->size); - *length = epaddr->size; - return TRUE; -} - -static gboolean -ethtool_supports_carrier_detect (const char *ifname) -{ - struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK }; - - /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we - * assume the device supports carrier-detect, otherwise we assume it - * doesn't. - */ - return ethtool_get (ifname, &edata); -} - -static gboolean -ethtool_supports_vlans (const char *ifname) -{ - gs_free struct ethtool_gfeatures *features = NULL; - int idx, block, bit, size; - - if (!ifname) - return FALSE; - - idx = ethtool_get_stringset_index (ifname, ETH_SS_FEATURES, "vlan-challenged"); - if (idx == -1) { - debug ("vlan-challenged ethtool feature does not exist?"); - return FALSE; - } - - block = idx / 32; - bit = idx % 32; - size = block + 1; - - features = g_malloc0 (sizeof (*features) + size * sizeof (struct ethtool_get_features_block)); - features->cmd = ETHTOOL_GFEATURES; - features->size = size; - - if (!ethtool_get (ifname, features)) - return FALSE; - - return !(features->features[block].active & (1 << bit)); -} - -static int -ethtool_get_peer_ifindex (const char *ifname) -{ - gs_free struct ethtool_stats *stats = NULL; - int peer_ifindex_stat; - - if (!ifname) - return 0; - - peer_ifindex_stat = ethtool_get_stringset_index (ifname, ETH_SS_STATS, "peer_ifindex"); - if (peer_ifindex_stat == -1) { - debug ("%s: peer_ifindex ethtool stat does not exist?", ifname); - return FALSE; - } - - stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64)); - stats->cmd = ETHTOOL_GSTATS; - stats->n_stats = peer_ifindex_stat + 1; - if (!ethtool_get (ifname, stats)) - return 0; - - return stats->data[peer_ifindex_stat]; -} - -static gboolean -ethtool_get_wake_on_lan (const char *ifname) -{ - struct ethtool_wolinfo wol; - - if (!ifname) - return FALSE; - - memset (&wol, 0, sizeof (wol)); - wol.cmd = ETHTOOL_GWOL; - if (!ethtool_get (ifname, &wol)) - return FALSE; - - return wol.wolopts != 0; -} - /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -1074,7 +875,7 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) } /* Fallback OVS detection for kernel <= 3.16 */ - if (ethtool_get_driver_info (ifname, &driver, NULL, NULL)) { + if (nmp_utils_ethtool_get_driver_info (ifname, &driver, NULL, NULL)) { if (!g_strcmp0 (driver, "openvswitch")) return NM_LINK_TYPE_OPENVSWITCH; } @@ -1151,7 +952,7 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin if (!info->driver) info->driver = info->kind; if (!info->driver) { - if (ethtool_get_driver_info (name, &tmp, NULL, NULL)) { + if (nmp_utils_ethtool_get_driver_info (name, &tmp, NULL, NULL)) { info->driver = g_intern_string (tmp); g_free (tmp); } @@ -2834,7 +2635,7 @@ link_supports_carrier_detect (NMPlatform *platform, int ifindex) * us whether the device actually supports carrier detection in the first * place. We assume any device that does implements one of these two APIs. */ - return ethtool_supports_carrier_detect (name) || supports_mii_carrier_detect (name); + return nmp_utils_ethtool_supports_carrier_detect (name) || supports_mii_carrier_detect (name); } static gboolean @@ -2846,7 +2647,7 @@ link_supports_vlans (NMPlatform *platform, int ifindex) if (!rtnllink || rtnl_link_get_arptype (rtnllink) != ARPHRD_ETHER) return FALSE; - return ethtool_supports_vlans (rtnl_link_get_name (rtnllink)); + return nmp_utils_ethtool_supports_vlans (rtnl_link_get_name (rtnllink)); } static gboolean @@ -2897,7 +2698,7 @@ link_get_permanent_address (NMPlatform *platform, guint8 *buf, size_t *length) { - return ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length); + return nmp_utils_ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length); } static gboolean @@ -3300,7 +3101,7 @@ veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties if (!ifname) return FALSE; - peer_ifindex = ethtool_get_peer_ifindex (ifname); + peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (ifname); if (peer_ifindex <= 0) return FALSE; @@ -3804,7 +3605,7 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) NMLinkType type = link_get_type (platform, ifindex); if (type == NM_LINK_TYPE_ETHERNET) - return ethtool_get_wake_on_lan (link_get_name (platform, ifindex)); + return nmp_utils_ethtool_get_wake_on_lan (link_get_name (platform, ifindex)); else if (type == NM_LINK_TYPE_WIFI) { WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); @@ -3823,10 +3624,10 @@ link_get_driver_info (NMPlatform *platform, char **out_driver_version, char **out_fw_version) { - return ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex), - out_driver_name, - out_driver_version, - out_fw_version); + return nmp_utils_ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex), + out_driver_name, + out_driver_version, + out_fw_version); } /******************************************************************/ diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 62127142cb..e13a91dcdc 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -20,6 +20,217 @@ #include "nm-platform-utils.h" +#include +#include +#include +#include +#include +#include + +#include "gsystem-local-alloc.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "nm-logging.h" + + +/****************************************************************** + * ethtool + ******************************************************************/ + +static gboolean +ethtool_get (const char *name, gpointer edata) +{ + struct ifreq ifr; + int fd; + + if (!name || !*name) + return FALSE; + + memset (&ifr, 0, sizeof (ifr)); + strncpy (ifr.ifr_name, name, IFNAMSIZ); + ifr.ifr_data = edata; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + nm_log_err (LOGD_PLATFORM, "ethtool: Could not open socket."); + return FALSE; + } + + if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { + nm_log_dbg (LOGD_PLATFORM, "ethtool: Request failed: %s", strerror (errno)); + close (fd); + return FALSE; + } + + close (fd); + return TRUE; +} + +static int +ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *string) +{ + gs_free struct ethtool_sset_info *info = NULL; + gs_free struct ethtool_gstrings *strings = NULL; + guint32 len, i; + + info = g_malloc0 (sizeof (*info) + sizeof (guint32)); + info->cmd = ETHTOOL_GSSET_INFO; + info->reserved = 0; + info->sset_mask = 1ULL << stringset_id; + + if (!ethtool_get (ifname, info)) + return -1; + if (!info->sset_mask) + return -1; + + len = info->data[0]; + + strings = g_malloc0 (sizeof (*strings) + len * ETH_GSTRING_LEN); + strings->cmd = ETHTOOL_GSTRINGS; + strings->string_set = stringset_id; + strings->len = len; + if (!ethtool_get (ifname, strings)) + return -1; + + for (i = 0; i < len; i++) { + if (!strcmp ((char *) &strings->data[i * ETH_GSTRING_LEN], string)) + return i; + } + + return -1; +} + +gboolean +nmp_utils_ethtool_get_driver_info (const char *ifname, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + struct ethtool_drvinfo drvinfo = { 0 }; + + if (!ifname) + return FALSE; + + drvinfo.cmd = ETHTOOL_GDRVINFO; + if (!ethtool_get (ifname, &drvinfo)) + return FALSE; + + if (out_driver_name) + *out_driver_name = g_strdup (drvinfo.driver); + if (out_driver_version) + *out_driver_version = g_strdup (drvinfo.version); + if (out_fw_version) + *out_fw_version = g_strdup (drvinfo.fw_version); + + return TRUE; +} + +gboolean +nmp_utils_ethtool_get_permanent_address (const char *ifname, + guint8 *buf, + size_t *length) +{ + gs_free struct ethtool_perm_addr *epaddr = NULL; + + if (!ifname) + return FALSE; + + epaddr = g_malloc0 (sizeof (*epaddr) + NM_UTILS_HWADDR_LEN_MAX); + epaddr->cmd = ETHTOOL_GPERMADDR; + epaddr->size = NM_UTILS_HWADDR_LEN_MAX; + + if (!ethtool_get (ifname, epaddr)) + return FALSE; + if (!nm_ethernet_address_is_valid (epaddr->data, epaddr->size)) + return FALSE; + + g_assert (epaddr->size <= NM_UTILS_HWADDR_LEN_MAX); + memcpy (buf, epaddr->data, epaddr->size); + *length = epaddr->size; + return TRUE; +} + +gboolean +nmp_utils_ethtool_supports_carrier_detect (const char *ifname) +{ + struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK }; + + /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we + * assume the device supports carrier-detect, otherwise we assume it + * doesn't. + */ + return ethtool_get (ifname, &edata); +} + +gboolean +nmp_utils_ethtool_supports_vlans (const char *ifname) +{ + gs_free struct ethtool_gfeatures *features = NULL; + int idx, block, bit, size; + + if (!ifname) + return FALSE; + + idx = ethtool_get_stringset_index (ifname, ETH_SS_FEATURES, "vlan-challenged"); + if (idx == -1) { + nm_log_dbg (LOGD_PLATFORM, "ethtool: vlan-challenged ethtool feature does not exist for %s?", ifname); + return FALSE; + } + + block = idx / 32; + bit = idx % 32; + size = block + 1; + + features = g_malloc0 (sizeof (*features) + size * sizeof (struct ethtool_get_features_block)); + features->cmd = ETHTOOL_GFEATURES; + features->size = size; + + if (!ethtool_get (ifname, features)) + return FALSE; + + return !(features->features[block].active & (1 << bit)); +} + +int +nmp_utils_ethtool_get_peer_ifindex (const char *ifname) +{ + gs_free struct ethtool_stats *stats = NULL; + int peer_ifindex_stat; + + if (!ifname) + return 0; + + peer_ifindex_stat = ethtool_get_stringset_index (ifname, ETH_SS_STATS, "peer_ifindex"); + if (peer_ifindex_stat == -1) { + nm_log_dbg (LOGD_PLATFORM, "ethtool: peer_ifindex stat for %s does not exist?", ifname); + return FALSE; + } + + stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64)); + stats->cmd = ETHTOOL_GSTATS; + stats->n_stats = peer_ifindex_stat + 1; + if (!ethtool_get (ifname, stats)) + return 0; + + return stats->data[peer_ifindex_stat]; +} + +gboolean +nmp_utils_ethtool_get_wake_on_lan (const char *ifname) +{ + struct ethtool_wolinfo wol; + + if (!ifname) + return FALSE; + + memset (&wol, 0, sizeof (wol)); + wol.cmd = ETHTOOL_GWOL; + if (!ethtool_get (ifname, &wol)) + return FALSE; + + return wol.wolopts != 0; +} + /****************************************************************** * udev ******************************************************************/ diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index 76f285d7d0..ba34a1fcb8 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -28,6 +28,22 @@ #include "nm-platform.h" +const char *nmp_utils_ethtool_get_driver (const char *ifname); +gboolean nmp_utils_ethtool_supports_carrier_detect (const char *ifname); +gboolean nmp_utils_ethtool_supports_vlans (const char *ifname); +int nmp_utils_ethtool_get_peer_ifindex (const char *ifname); +gboolean nmp_utils_ethtool_get_wake_on_lan (const char *ifname); + +gboolean nmp_utils_ethtool_get_driver_info (const char *ifname, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version); + +gboolean nmp_utils_ethtool_get_permanent_address (const char *ifname, + guint8 *buf, + size_t *length); + + const char *nmp_utils_udev_get_driver (GUdevDevice *device); From f9760da1a1ab8749c43d70d61e52c762bc4af26b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 3 May 2015 12:49:46 +0200 Subject: [PATCH 14/17] platform: move supports_mii_carrier_detect() to nmp_utils_mii_supports_carrier_detect() (cherry picked from commit 299af02e40bc0a19d4a2e021cd7250adf1cfbb86) --- src/platform/nm-linux-platform.c | 45 +--------------------------- src/platform/nm-platform-utils.c | 50 ++++++++++++++++++++++++++++++++ src/platform/nm-platform-utils.h | 3 ++ 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 735a0b8834..548265cf32 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -31,9 +31,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -2583,46 +2580,6 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable return FALSE; } -static gboolean -supports_mii_carrier_detect (const char *ifname) -{ - int fd; - struct ifreq ifr; - struct mii_ioctl_data *mii; - gboolean supports_mii = FALSE; - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - nm_log_err (LOGD_PLATFORM, "couldn't open control socket."); - return FALSE; - } - - memset (&ifr, 0, sizeof (struct ifreq)); - strncpy (ifr.ifr_name, ifname, IFNAMSIZ); - - errno = 0; - if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) { - nm_log_dbg (LOGD_PLATFORM, "SIOCGMIIPHY failed: %d", errno); - goto out; - } - - /* If we can read the BMSR register, we assume that the card supports MII link detection */ - mii = (struct mii_ioctl_data *) &ifr.ifr_ifru; - mii->reg_num = MII_BMSR; - - if (ioctl (fd, SIOCGMIIREG, &ifr) == 0) { - nm_log_dbg (LOGD_PLATFORM, "SIOCGMIIREG result 0x%X", mii->val_out); - supports_mii = TRUE; - } else { - nm_log_dbg (LOGD_PLATFORM, "SIOCGMIIREG failed: %d", errno); - } - - out: - close (fd); - nm_log_dbg (LOGD_PLATFORM, "MII %s supported", supports_mii ? "is" : "not"); - return supports_mii; -} - static gboolean link_supports_carrier_detect (NMPlatform *platform, int ifindex) { @@ -2635,7 +2592,7 @@ link_supports_carrier_detect (NMPlatform *platform, int ifindex) * us whether the device actually supports carrier detection in the first * place. We assume any device that does implements one of these two APIs. */ - return nmp_utils_ethtool_supports_carrier_detect (name) || supports_mii_carrier_detect (name); + return nmp_utils_ethtool_supports_carrier_detect (name) || nmp_utils_mii_supports_carrier_detect (name); } static gboolean diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index e13a91dcdc..17a82c1a56 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "gsystem-local-alloc.h" #include "nm-utils.h" @@ -231,6 +232,55 @@ nmp_utils_ethtool_get_wake_on_lan (const char *ifname) return wol.wolopts != 0; } +/****************************************************************** + * mii + ******************************************************************/ + +gboolean +nmp_utils_mii_supports_carrier_detect (const char *ifname) +{ + int fd, errsv; + struct ifreq ifr; + struct mii_ioctl_data *mii; + gboolean supports_mii = FALSE; + + if (!ifname) + return FALSE; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + nm_log_err (LOGD_PLATFORM, "mii: couldn't open control socket (%s)", ifname); + return FALSE; + } + + memset (&ifr, 0, sizeof (struct ifreq)); + strncpy (ifr.ifr_name, ifname, IFNAMSIZ); + + errno = 0; + if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) { + errsv = errno; + nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIPHY failed: %s (%d) (%s)", strerror (errsv), errsv, ifname); + goto out; + } + + /* If we can read the BMSR register, we assume that the card supports MII link detection */ + mii = (struct mii_ioctl_data *) &ifr.ifr_ifru; + mii->reg_num = MII_BMSR; + + if (ioctl (fd, SIOCGMIIREG, &ifr) == 0) { + nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIREG result 0x%X (%s)", mii->val_out, ifname); + supports_mii = TRUE; + } else { + errsv = errno; + nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIREG failed: %s (%d) (%s)", strerror (errsv), errsv, ifname); + } + +out: + close (fd); + nm_log_dbg (LOGD_PLATFORM, "mii: MII %s supported (%s)", supports_mii ? "is" : "not", ifname); + return supports_mii; +} + /****************************************************************** * udev ******************************************************************/ diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index ba34a1fcb8..edc55c09cd 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -44,6 +44,9 @@ gboolean nmp_utils_ethtool_get_permanent_address (const char *ifname, size_t *length); +gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname); + + const char *nmp_utils_udev_get_driver (GUdevDevice *device); From adcd51065bb121e2b1190673269e59dda741b157 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 1 Jun 2015 12:06:12 +0200 Subject: [PATCH 15/17] platform: move ethtool_get_link_speed() to nm-platform-utils (cherry picked from commit 95333d84bcaef7b450293b8fbc4550a30fad2df3) --- src/devices/nm-device-ethernet.c | 34 ++------------------------------ src/platform/nm-platform-utils.c | 25 +++++++++++++++++++++++ src/platform/nm-platform-utils.h | 1 + 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index bc5273f531..274f6b1cc7 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -26,10 +26,6 @@ #include #include #include -#include -#include -#include -#include #include #include @@ -48,6 +44,7 @@ #include "nm-enum-types.h" #include "nm-dbus-manager.h" #include "nm-platform.h" +#include "nm-platform-utils.h" #include "nm-dcb.h" #include "nm-settings-connection.h" #include "nm-config.h" @@ -1508,37 +1505,10 @@ get_link_speed (NMDevice *device) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - struct ifreq ifr; - struct ethtool_cmd edata = { - .cmd = ETHTOOL_GSET, - }; guint32 speed; - int fd; - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW | LOGD_ETHER, "couldn't open ethtool control socket."); + if (!nmp_utils_ethtool_get_link_speed (nm_device_get_iface (device), &speed)) return; - } - - memset (&ifr, 0, sizeof (struct ifreq)); - strncpy (ifr.ifr_name, nm_device_get_iface (device), IFNAMSIZ); - ifr.ifr_data = (char *) &edata; - - if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { - close (fd); - return; - } - close (fd); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - speed = edata.speed; -#else - speed = ethtool_cmd_speed (&edata); -#endif - if (speed == G_MAXUINT16 || speed == G_MAXUINT32) - speed = 0; - if (priv->speed == speed) return; diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 17a82c1a56..407b91fbcc 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "gsystem-local-alloc.h" #include "nm-utils.h" @@ -232,6 +233,30 @@ nmp_utils_ethtool_get_wake_on_lan (const char *ifname) return wol.wolopts != 0; } +gboolean +nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed) +{ + struct ethtool_cmd edata = { + .cmd = ETHTOOL_GSET, + }; + guint32 speed; + + if (!ethtool_get (ifname, &edata)) + return FALSE; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + speed = edata.speed; +#else + speed = ethtool_cmd_speed (&edata); +#endif + if (speed == G_MAXUINT16 || speed == G_MAXUINT32) + speed = 0; + + if (out_speed) + *out_speed = speed; + return TRUE; +} + /****************************************************************** * mii ******************************************************************/ diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index edc55c09cd..d0032f5d69 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -33,6 +33,7 @@ gboolean nmp_utils_ethtool_supports_carrier_detect (const char *ifname); gboolean nmp_utils_ethtool_supports_vlans (const char *ifname); int nmp_utils_ethtool_get_peer_ifindex (const char *ifname); gboolean nmp_utils_ethtool_get_wake_on_lan (const char *ifname); +gboolean nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed); gboolean nmp_utils_ethtool_get_driver_info (const char *ifname, char **out_driver_name, From 8f6a883c73979ec9b775d25a4560cd5538401574 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 6 May 2015 11:55:02 +0200 Subject: [PATCH 16/17] platform: refactor support_kernel_extended_ifa_flags to static variable Whether we have support depends on the kernel, and is not per NMLinuxPlatform instance. (cherry picked from commit 2f3fd86dc559a51513ba340a094c4f48710ea68c) --- src/platform/nm-linux-platform.c | 85 +++++++++++++++++--------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 548265cf32..88f27aab0f 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -359,6 +359,47 @@ _support_user_ipv6ll_detect (const struct rtnl_link *rtnl_link) #endif } +/******************************************************************/ + +static int _support_kernel_extended_ifa_flags = 0; + +#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0)) + +static void +_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) +{ + struct nlmsghdr *msg_hdr = nlmsg_hdr (msg); + + if (!_support_kernel_extended_ifa_flags_still_undecided ()) + return; + + msg_hdr = nlmsg_hdr (msg); + if (msg_hdr->nlmsg_type != RTM_NEWADDR) + return; + + /* the extended address flags are only set for AF_INET6 */ + if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6) + return; + + /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, + * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR + * and IFA_F_NOPREFIXROUTE (they were added together). + **/ + _support_kernel_extended_ifa_flags = + nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */) + ? 1 : -1; +} + +static gboolean +_support_kernel_extended_ifa_flags_get () +{ + if (_support_kernel_extended_ifa_flags_still_undecided ()) { + nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for extended IFA_FLAGS. Assume no kernel support."); + _support_kernel_extended_ifa_flags = -1; + } + return _support_kernel_extended_ifa_flags > 0; +} + /****************************************************************** * NMPlatform types and functions ******************************************************************/ @@ -389,8 +430,6 @@ typedef struct { GHashTable *udev_devices; GHashTable *wifi_data; - - int support_kernel_extended_ifa_flags; } NMLinuxPlatformPrivate; #define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate)) @@ -663,42 +702,12 @@ nm_rtnl_link_parse_info_data (struct nl_sock *sk, int ifindex, /******************************************************************/ -static void -_check_support_kernel_extended_ifa_flags_init (NMLinuxPlatformPrivate *priv, struct nl_msg *msg) -{ - struct nlmsghdr *msg_hdr = nlmsg_hdr (msg); - - g_return_if_fail (priv->support_kernel_extended_ifa_flags == 0); - g_return_if_fail (msg_hdr->nlmsg_type == RTM_NEWADDR); - - /* the extended address flags are only set for AF_INET6 */ - if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6) - return; - - /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, - * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR - * and IFA_F_NOPREFIXROUTE (they were added together). - **/ - priv->support_kernel_extended_ifa_flags = - nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */) - ? 1 : -1; -} - static gboolean check_support_kernel_extended_ifa_flags (NMPlatform *platform) { - NMLinuxPlatformPrivate *priv; - g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); - priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - - if (priv->support_kernel_extended_ifa_flags == 0) { - nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for extended IFA_FLAGS. Assume no kernel support."); - priv->support_kernel_extended_ifa_flags = -1; - } - - return priv->support_kernel_extended_ifa_flags > 0; + return _support_kernel_extended_ifa_flags_get (); } static gboolean @@ -1904,12 +1913,8 @@ event_notification (struct nl_msg *msg, gpointer user_data) event = nlmsg_hdr (msg)->nlmsg_type; - if (priv->support_kernel_extended_ifa_flags == 0 && event == RTM_NEWADDR) { - /* if kernel support for extended ifa flags is still undecided, use the opportunity - * now and use @msg to decide it. This saves a blocking net link request. - **/ - _check_support_kernel_extended_ifa_flags_init (priv, msg); - } + if (_support_kernel_extended_ifa_flags_still_undecided () && event == RTM_NEWADDR) + _support_kernel_extended_ifa_flags_detect (msg); nl_msg_parse (msg, ref_object, &object); if (!object) @@ -3711,7 +3716,7 @@ build_rtnl_addr (NMPlatform *platform, rtnl_addr_set_preferred_lifetime (rtnladdr, preferred); } if (flags) { - if ((flags & ~0xFF) && !check_support_kernel_extended_ifa_flags (platform)) { + if ((flags & ~0xFF) && !_support_kernel_extended_ifa_flags_get ()) { /* Older kernels don't accept unknown netlink attributes. * * With commit libnl commit 5206c050504f8676a24854519b9c351470fb7cc6, libnl will only set From 072296750cc74224f9f34d81891538385fba63f1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 24 Apr 2015 12:28:07 +0200 Subject: [PATCH 17/17] platform: expose nm_platform_signal_change_type_to_string() (cherry picked from commit d4f828c887baf7e2dd45825dc53d742a4b07452f) --- src/platform/nm-platform.c | 14 +++++++------- src/platform/nm-platform.h | 2 ++ src/platform/tests/test-common.c | 19 ++----------------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 79e83b6aef..82014faa8b 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3082,8 +3082,8 @@ nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatfor #undef _CMP_POINTER -static const char * -_change_type_to_string (NMPlatformSignalChangeType change_type) +const char * +nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type) { switch (change_type) { case NM_PLATFORM_SIGNAL_ADDED: @@ -3101,31 +3101,31 @@ static void log_link (NMPlatform *p, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: link %7s: %s", _change_type_to_string (change_type), nm_platform_link_to_string (device)); + debug ("signal: link %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_link_to_string (device)); } static void log_ip4_address (NMPlatform *p, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: address 4 %7s: %s", _change_type_to_string (change_type), nm_platform_ip4_address_to_string (address)); + debug ("signal: address 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_address_to_string (address)); } static void log_ip6_address (NMPlatform *p, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: address 6 %7s: %s", _change_type_to_string (change_type), nm_platform_ip6_address_to_string (address)); + debug ("signal: address 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_address_to_string (address)); } static void log_ip4_route (NMPlatform *p, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: route 4 %7s: %s", _change_type_to_string (change_type), nm_platform_ip4_route_to_string (route)); + debug ("signal: route 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_route_to_string (route)); } static void log_ip6_route (NMPlatform *p, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) { - debug ("signal: route 6 %7s: %s", _change_type_to_string (change_type), nm_platform_ip6_route_to_string (route)); + debug ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route)); } /******************************************************************/ diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 5b42968733..9b267e548c 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -514,6 +514,8 @@ typedef struct { #define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed" #define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed" +const char *nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type); + /******************************************************************/ GType nm_platform_get_type (void); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 6170e403eb..8b4eb0465a 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -8,7 +8,7 @@ #include "nm-test-utils.h" #define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)" -#define SIGNAL_DATA_ARG(data) (data)->name, _change_type_to_string ((data)->change_type), (data)->ifindex, (data)->ifname ? " ifname '" : "", (data)->ifname ? (data)->ifname : "", (data)->ifname ? "'" : "", (data)->received_count +#define SIGNAL_DATA_ARG(data) (data)->name, nm_platform_signal_change_type_to_string ((data)->change_type), (data)->ifindex, (data)->ifname ? " ifname '" : "", (data)->ifname ? (data)->ifname : "", (data)->ifname ? "'" : "", (data)->received_count gboolean @@ -43,21 +43,6 @@ add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCall return data; } -static const char * -_change_type_to_string (NMPlatformSignalChangeType change_type) -{ - switch (change_type) { - case NM_PLATFORM_SIGNAL_ADDED: - return "added"; - case NM_PLATFORM_SIGNAL_CHANGED: - return "changed"; - case NM_PLATFORM_SIGNAL_REMOVED: - return "removed"; - default: - g_return_val_if_reached ("UNKNOWN"); - } -} - void _accept_signal (const char *file, int line, const char *func, SignalData *data) { @@ -134,7 +119,7 @@ link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPl } data->received_count++; - debug ("Received signal '%s-%s' ifindex %d ifname '%s' %dth time.", data->name, _change_type_to_string (data->change_type), ifindex, received->name, data->received_count); + debug ("Received signal '%s-%s' ifindex %d ifname '%s' %dth time.", data->name, nm_platform_signal_change_type_to_string (data->change_type), ifindex, received->name, data->received_count); if (change_type == NM_PLATFORM_SIGNAL_REMOVED) g_assert (!nm_platform_link_get_name (NM_PLATFORM_GET, ifindex));