platform: merge branch 'th/platform_refact_caching-bgo747981' (early part)

- add new file 'nm-platform-utils.c' and moves some independent utility
  functions there (ethtool, udev).
- some refactoring of platform code, including initialization of
  NMPlatform instance.
- run platform tests in a separate user namespace, which allow
  us to run root-tests as non-root.

https://bugzilla.gnome.org/show_bug.cgi?id=747981
This commit is contained in:
Thomas Haller 2015-06-05 16:11:47 +02:00
commit d38c3851f8
19 changed files with 692 additions and 446 deletions

View file

@ -105,7 +105,7 @@
#ifdef NM_MORE_ASSERTS
#define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END
#else
#define nm_assert(cond) G_STMT_START { (void) 0; } G_STMT_END
#define nm_assert(cond) G_STMT_START { if (FALSE) { if (cond) { } } } G_STMT_END
#endif
/*****************************************************************************/
@ -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__ */

View file

@ -225,6 +225,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 \
@ -464,6 +466,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 \

View file

@ -303,8 +303,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;
@ -312,6 +323,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);
@ -329,12 +342,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;
}

View file

@ -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:

View file

@ -26,10 +26,6 @@
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#include <linux/version.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
@ -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"
@ -1533,37 +1530,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;

View file

@ -1109,7 +1109,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 {
@ -5294,7 +5301,7 @@ share_init (void)
}
for (iter = modules; *iter; iter++)
nm_utils_modprobe (NULL, *iter, NULL);
nm_utils_modprobe (NULL, FALSE, *iter, NULL);
return TRUE;
}

View file

@ -1936,6 +1936,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,
@ -3946,7 +3961,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

View file

@ -31,10 +31,6 @@
#include <linux/if_link.h>
#include <linux/if_tun.h>
#include <linux/if_tunnel.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <netlink/netlink.h>
#include <netlink/object.h>
#include <netlink/cache.h>
@ -58,6 +54,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"
@ -362,162 +359,45 @@ _support_user_ipv6ll_detect (const struct rtnl_link *rtnl_link)
#endif
}
/******************************************************************
* ethtool
******************************************************************/
/******************************************************************/
static gboolean
ethtool_get (const char *name, gpointer edata)
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 ifreq ifr;
int fd;
struct nlmsghdr *msg_hdr = nlmsg_hdr (msg);
if (!name || !*name)
return FALSE;
if (!_support_kernel_extended_ifa_flags_still_undecided ())
return;
memset (&ifr, 0, sizeof (ifr));
strncpy (ifr.ifr_name, name, IFNAMSIZ);
ifr.ifr_data = edata;
msg_hdr = nlmsg_hdr (msg);
if (msg_hdr->nlmsg_type != RTM_NEWADDR)
return;
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
error ("ethtool: Could not open socket.");
return FALSE;
}
/* the extended address flags are only set for AF_INET6 */
if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
return;
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;
/* 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
ethtool_get_driver_info (const char *ifname,
char **out_driver_name,
char **out_driver_version,
char **out_fw_version)
_support_kernel_extended_ifa_flags_get ()
{
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;
}
/******************************************************************
* 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);
}
}
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;
}
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);
return _support_kernel_extended_ifa_flags > 0;
}
/******************************************************************
@ -550,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))
@ -824,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
@ -1033,7 +881,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;
}
@ -1102,7 +950,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;
}
@ -1110,7 +958,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);
}
@ -2065,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)
@ -2439,7 +2283,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)",
@ -2741,58 +2585,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)
{
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)
{
@ -2805,42 +2597,19 @@ 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 nmp_utils_ethtool_supports_carrier_detect (name) || nmp_utils_mii_supports_carrier_detect (name);
}
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 nmp_utils_ethtool_supports_vlans (rtnl_link_get_name (rtnllink));
}
static gboolean
@ -2891,7 +2660,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
@ -3288,26 +3057,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 = nmp_utils_ethtool_get_peer_ifindex (ifname);
if (peer_ifindex <= 0)
return FALSE;
props->peer = stats->data[peer_ifindex_stat];
props->peer = peer_ifindex;
return TRUE;
}
@ -3805,16 +3565,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 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);
if (!wifi_data)
@ -3832,10 +3585,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);
}
/******************************************************************/
@ -3962,7 +3715,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
@ -4774,6 +4527,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);
@ -4838,16 +4593,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");
@ -4861,6 +4606,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
@ -4898,8 +4645,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;

View file

@ -0,0 +1,350 @@
/* -*- 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 <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <linux/mii.h>
#include <linux/version.h>
#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;
}
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
******************************************************************/
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
******************************************************************/
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);
}

View file

@ -0,0 +1,54 @@
/* -*- 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 <gudev/gudev.h>
#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_link_speed (const char *ifname, guint32 *out_speed);
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);
gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname);
const char *nmp_utils_udev_get_driver (GUdevDevice *device);
#endif /* __NM_PLATFORM_UTILS_H__ */

View file

@ -381,36 +381,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);
/* Platform specific device setup. */
if (klass->setup_devices)
klass->setup_devices (self);
}
/**
* nm_platform_link_get_all:
* self: platform instance
@ -2915,8 +2885,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:
@ -2934,31 +2904,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));
}
/******************************************************************/

View file

@ -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);
@ -517,6 +515,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);
@ -535,8 +535,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);

View file

@ -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

View file

@ -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 \

View file

@ -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
@ -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)
{
@ -36,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)
{
@ -127,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));
@ -278,6 +270,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)
{
@ -286,17 +318,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")) {
@ -325,12 +361,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);
}
}
}

View file

@ -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)

View file

@ -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 ();
}

View file

@ -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;

View file

@ -1071,7 +1071,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);