mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-09 15:50:26 +01:00
platform: move ethtool_*() to nmp_utils_ethtool_*()
This commit is contained in:
parent
398819c3ac
commit
ac84b22fc7
3 changed files with 238 additions and 210 deletions
|
|
@ -33,7 +33,6 @@
|
|||
#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>
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -3803,7 +3604,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);
|
||||
|
||||
|
|
@ -3822,10 +3623,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);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,217 @@
|
|||
|
||||
#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 "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
|
||||
******************************************************************/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue