IOCTL 获取网络信息(Ethtool工具)

1. 网络属性

# ifconfig  eth0                                                   
eth0      Link encap:Ethernet  HWaddr b0:d5:68:e1:e2:29
          inet addr:192.168.5.135  Bcast:192.168.5.255  Mask:255.255.255.0 
          inet6 addr: fe80::b2d5:68ff:fee1:e229/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:13782 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:3563 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:3492265 TX bytes:2128056 
          Interrupt:41 Base address:0x4000 

# ifconfig eth1                                                    
eth1      Link encap:Ethernet  HWaddr b0:d5:68:e1:e2:92  Driver r8152
          inet addr:192.168.5.1  Bcast:192.168.5.255  Mask:255.255.255.0 
          inet6 addr: fe80::b2d5:68ff:fee1:e292/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:3433 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:0 TX bytes:2109366 

linux 下,输入ifconfig ehtX 指令,我们可以看到以太网的很多属性,例如网卡0 有Link encap,HWaddr,inet addr, Bcast, Mask,inet6 addr, Scope,MTU, Metric,RX packets, errors, dropped, overruns, frame, TX packets, errors, dropped, overruns, carrier, collisions, txqueuelen, RX bytes, TX bytes, Interrupt, Base address,这些属性。这些属性和驱动节点属性部分是对应的
在这里插入图片描述
上传获取这些属性通常比较方便,但是底层不是那边方便,可以底层能获取的信息更全更完整。linux c/c++ 编程人员通常可以通过文件节点,或者ethtool 工具来获取网络的一些属性。

Ethtool 工具

简言之,是linux 下查询,设置网卡属性,配置的工具。

案例

下面分享用户态编程获取网卡属性。

  1. 获取属性个数
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>

#include <linux/sockios.h>
#include <linux/ethtool.h>

int main(int argc, char* argv[])
{
    int fd;
    int ret;
    unsigned int n_stats, i;
    struct ifreq ifr;
    struct {
        struct ethtool_sset_info hdr;
        unsigned int buf[1];
    } sset_info;

    struct ethtool_stats *stats;
    struct ethtool_gstrings *strings;
    unsigned int sz_stats;

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
        sset_info.hdr.reserved = 0;
        sset_info.hdr.sset_mask = 1ULL << ETH_SS_STATS;

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, "eth0");
    ifr.ifr_data = (void*)&sset_info;
    ret = ioctl(fd, SIOCETHTOOL, &ifr);
    if (0 != ret) {
        printf("errno=%d\n", errno);
        return -1;
    }

    n_stats = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0;
    printf("stats count = %d\n", n_stats);
}

  1. 获取属性列表
    在第1步的基础上
strings = calloc(1, sizeof(*strings) + n_stats * ETH_GSTRING_LEN);
        if (!strings)
                return -1;

        strings->cmd = ETHTOOL_GSTRINGS;
        strings->string_set = ETH_SS_STATS;
        strings->len = n_stats;

    memset(&ifr, 0, sizeof(ifr));
        strcpy(ifr.ifr_name, "eth0");
    ifr.ifr_data = (void*)strings;
    ret = ioctl(fd, SIOCETHTOOL, &ifr);
    if (0 != ret) {
        printf("ETH_SS_STATS, errno=%d\n", errno);
        return -1;
    }
  1. 获取列表各属性的值
    在第1步的基础上
    sz_stats = n_stats * sizeof(unsigned long long);
    stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
    stats->cmd = ETHTOOL_GSTATS;
    stats->n_stats = n_stats;

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, "eth0");
    ifr.ifr_data = (void*)stats;
    ret = ioctl(fd, SIOCETHTOOL, &ifr);
    if (0 != ret) {
        printf("errno=%d\n", errno);
        return -1;
    }

    for (i = 0; i < n_stats; i++) {
                printf("%llu\n", stats->data[i]);
    }

通过分析发现,操作socket 的主cmd 为SIOCETHTOOL,sub cmd 分别为ETHTOOL_GSSET_INFO,ETHTOOL_GSTRINGS,ETHTOOL_GSTATS。

假如我们的eth0 的网卡为8152B ,那么内核的流程就是:
在这里插入图片描述在这里插入图片描述
属性个数
在这里插入图片描述ethtool_get_sset_info 对调用__ethtool_get_sset_count,接着ethtool_ops->get_sset_count,最后调用到8152B驱动

vendor\mstar\kernel\linaro\drivers\net\usb\r8152.c
static const struct ethtool_ops ops = {
	......
	.get_strings = rtl8152_get_strings,
	.get_sset_count = rtl8152_get_sset_count,
	.get_ethtool_stats = rtl8152_get_ethtool_stats,
	......
}
static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = {
	"tx_packets",
	"rx_packets",
	"tx_errors",
	"rx_errors",
	"rx_missed",
	"align_errors",
	"tx_single_collisions",
	"tx_multi_collisions",
	"rx_unicast",
	"rx_broadcast",
	"rx_multicast",
	"tx_aborted",
	"tx_underrun",
};

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
static int rtl8152_get_sset_count(struct net_device *dev)
{
	return ARRAY_SIZE(rtl8152_gstrings);
}

rtl8152_get_sset_count 最后返回属性个数。

属性列表 及其 属性值列表
在这里插入图片描述
同样的流程, ethtool_get_strings ,ethtool_get_stats 会走到rtl8152_get_strings, rtl8152_get_ethtool_stats.

static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
	switch (stringset) {
	case ETH_SS_STATS:
		memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings));
		break;
	}
}

static void rtl8152_get_ethtool_stats(struct net_device *dev,
				      struct ethtool_stats *stats, u64 *data)
{
	struct r8152 *tp = netdev_priv(dev);
	struct tally_counter tally;

	if (usb_autopm_get_interface(tp->intf) < 0)
		return;

	if (mutex_lock_interruptible(&tp->control) < 0) {
		usb_autopm_put_interface(tp->intf);
		return;
	}

	generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA);

	mutex_unlock(&tp->control);

	usb_autopm_put_interface(tp->intf);

	data[0] = le64_to_cpu(tally.tx_packets);
	data[1] = le64_to_cpu(tally.rx_packets);
	data[2] = le64_to_cpu(tally.tx_errors);
	data[3] = le32_to_cpu(tally.rx_errors);
	data[4] = le16_to_cpu(tally.rx_missed);
	data[5] = le16_to_cpu(tally.align_errors);
	data[6] = le32_to_cpu(tally.tx_one_collision);
	data[7] = le32_to_cpu(tally.tx_multi_collision);
	data[8] = le64_to_cpu(tally.rx_unicast);
	data[9] = le64_to_cpu(tally.rx_broadcast);
	data[10] = le32_to_cpu(tally.rx_multicast);
	data[11] = le16_to_cpu(tally.tx_aborted);
	data[12] = le16_to_cpu(tally.tx_underrun);
}

这样就完成了从用户态,ethtool ,网卡驱动信息的获取流程。

  • 示例-获取link 状态
#include  <linux/ethtool.h>
#include  <linux/sockios.h>
int detectEthernetLinkState()
{
    int skfd;
    struct ifreq ifr;
    struct ethtool_value edata;
    char pIfName[5] = {0x00};
    edata.cmd = ETHTOOL_GLINK;  
    // vendor\mstar\kernel\linaro\mstar2\drv\emac\mdrv_emac.c  MDev_EMAC_ethtool_ioctl

    edata.data = 0;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(pIfName, "eth0", sizeof(pIfName)/sizeof(pIfName[0]));
    strncpy(ifr.ifr_name, pIfName, sizeof(ifr.ifr_name) - 1);
    ifr.ifr_data = (char *) &edata;
    if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 )) == 0)
    {
        close(skfd);
        return 0;
    }
    if(ioctl( skfd, SIOCETHTOOL, &ifr ) == -1)
    {
        close(skfd);
        return 0;
    }
    close(skfd);
    return edata.data;
}

也可以

int detectEthernetLinkState()
{
    int skfd = 0;
    struct ifreq ifr;

    skfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(skfd < 0) 
    {
        printf("%s:%d Open socket error!\n", __FILE__, __LINE__);
        return 0;
    }

    strcpy(ifr.ifr_name, "eth0");

    if(ioctl(skfd, SIOCGIFFLAGS, &ifr) <0 )
    {
        printf("%s:%d IOCTL error!\n", __FILE__, __LINE__);
        printf("Maybe ethernet inferface %s is not valid!", ifr.ifr_name);
        close(skfd);
        return 0;
    }

    if(ifr.ifr_flags & IFF_RUNNING)
    {
        close(skfd);
        return 1;
    }
    else
    {
        close(skfd);
        return 0;
    }
}

根据驱动提供的方法,我们可以根据主cmd ,sub cmd 在用户态查找属性,设置参数。
sub cmd 如下

vendor\mstar\kernel\linaro\include\uapi\linux\ethtool.h
/* CMDs currently supported */
#define ETHTOOL_GSET		0x00000001 /* DEPRECATED, Get settings.
					    * Please use ETHTOOL_GLINKSETTINGS
					    */
#define ETHTOOL_SSET		0x00000002 /* DEPRECATED, Set settings.
					    * Please use ETHTOOL_SLINKSETTINGS
					    */
#define ETHTOOL_GDRVINFO	0x00000003 /* Get driver info. */
#define ETHTOOL_GREGS		0x00000004 /* Get NIC registers. */
#define ETHTOOL_GWOL		0x00000005 /* Get wake-on-lan options. */
#define ETHTOOL_SWOL		0x00000006 /* Set wake-on-lan options. */
#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level. */
#define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation. */
/* Get link status for host, i.e. whether the interface *and* the
 * physical port (if there is one) are up (ethtool_value). */
#define ETHTOOL_GLINK		0x0000000a
#define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data. */
#define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config. */
#define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters. */
#define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters. */
#define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
#define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
#define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
#define ETHTOOL_STXCSUM		0x00000017 /* Set TX hw csum enable (ethtool_value) */
#define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
					    * (ethtool_value) */
#define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
					    * (ethtool_value). */
#define ETHTOOL_TEST		0x0000001a /* execute NIC self-test. */
#define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
#define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
#define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
#define ETHTOOL_GTSO		0x0000001e /* Get TSO enable (ethtool_value) */
#define ETHTOOL_STSO		0x0000001f /* Set TSO enable (ethtool_value) */
#define ETHTOOL_GPERMADDR	0x00000020 /* Get permanent hardware address */
#define ETHTOOL_GUFO		0x00000021 /* Get UFO enable (ethtool_value) */
#define ETHTOOL_SUFO		0x00000022 /* Set UFO enable (ethtool_value) */
#define ETHTOOL_GGSO		0x00000023 /* Get GSO enable (ethtool_value) */
#define ETHTOOL_SGSO		0x00000024 /* Set GSO enable (ethtool_value) */
#define ETHTOOL_GFLAGS		0x00000025 /* Get flags bitmap(ethtool_value) */
#define ETHTOOL_SFLAGS		0x00000026 /* Set flags bitmap(ethtool_value) */
#define ETHTOOL_GPFLAGS		0x00000027 /* Get driver-private flags bitmap */
#define ETHTOOL_SPFLAGS		0x00000028 /* Set driver-private flags bitmap */

#define ETHTOOL_GRXFH		0x00000029 /* Get RX flow hash configuration */
#define ETHTOOL_SRXFH		0x0000002a /* Set RX flow hash configuration */
#define ETHTOOL_GGRO		0x0000002b /* Get GRO enable (ethtool_value) */
#define ETHTOOL_SGRO		0x0000002c /* Set GRO enable (ethtool_value) */
#define ETHTOOL_GRXRINGS	0x0000002d /* Get RX rings available for LB */
#define ETHTOOL_GRXCLSRLCNT	0x0000002e /* Get RX class rule count */
#define ETHTOOL_GRXCLSRULE	0x0000002f /* Get RX classification rule */
#define ETHTOOL_GRXCLSRLALL	0x00000030 /* Get all RX classification rule */
#define ETHTOOL_SRXCLSRLDEL	0x00000031 /* Delete RX classification rule */
#define ETHTOOL_SRXCLSRLINS	0x00000032 /* Insert RX classification rule */
#define ETHTOOL_FLASHDEV	0x00000033 /* Flash firmware to device */
#define ETHTOOL_RESET		0x00000034 /* Reset hardware */
#define ETHTOOL_SRXNTUPLE	0x00000035 /* Add an n-tuple filter to device */
#define ETHTOOL_GRXNTUPLE	0x00000036 /* deprecated */
#define ETHTOOL_GSSET_INFO	0x00000037 /* Get string set info */
#define ETHTOOL_GRXFHINDIR	0x00000038 /* Get RX flow hash indir'n table */
#define ETHTOOL_SRXFHINDIR	0x00000039 /* Set RX flow hash indir'n table */

#define ETHTOOL_GFEATURES	0x0000003a /* Get device offload settings */
#define ETHTOOL_SFEATURES	0x0000003b /* Change device offload settings */
#define ETHTOOL_GCHANNELS	0x0000003c /* Get no of channels */
#define ETHTOOL_SCHANNELS	0x0000003d /* Set no of channels */
#define ETHTOOL_SET_DUMP	0x0000003e /* Set dump settings */
#define ETHTOOL_GET_DUMP_FLAG	0x0000003f /* Get dump settings */
#define ETHTOOL_GET_DUMP_DATA	0x00000040 /* Get dump data */
#define ETHTOOL_GET_TS_INFO	0x00000041 /* Get time stamping and PHC info */
#define ETHTOOL_GMODULEINFO	0x00000042 /* Get plug-in module information */
#define ETHTOOL_GMODULEEEPROM	0x00000043 /* Get plug-in module eeprom */
#define ETHTOOL_GEEE		0x00000044 /* Get EEE settings */
#define ETHTOOL_SEEE		0x00000045 /* Set EEE settings */

#define ETHTOOL_GRSSH		0x00000046 /* Get RX flow hash configuration */
#define ETHTOOL_SRSSH		0x00000047 /* Set RX flow hash configuration */
#define ETHTOOL_GTUNABLE	0x00000048 /* Get tunable configuration */
#define ETHTOOL_STUNABLE	0x00000049 /* Set tunable configuration */
#define ETHTOOL_GPHYSTATS	0x0000004a /* get PHY-specific statistics */

#define ETHTOOL_PERQUEUE	0x0000004b /* Set per queue options */

#define ETHTOOL_GLINKSETTINGS	0x0000004c /* Get ethtool_link_settings */
#define ETHTOOL_SLINKSETTINGS	0x0000004d /* Set ethtool_link_settings */

cmd 对应的驱动接口

struct ethtool_ops {
	int	(*get_settings)(struct net_device *, struct ethtool_cmd *);
	int	(*set_settings)(struct net_device *, struct ethtool_cmd *);
	void	(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
	int	(*get_regs_len)(struct net_device *);
	void	(*get_regs)(struct net_device *, struct ethtool_regs *, void *);
	void	(*get_wol)(struct net_device *, struct ethtool_wolinfo *);
	int	(*set_wol)(struct net_device *, struct ethtool_wolinfo *);
	u32	(*get_msglevel)(struct net_device *);
	void	(*set_msglevel)(struct net_device *, u32);
	int	(*nway_reset)(struct net_device *);
	u32	(*get_link)(struct net_device *);
	int	(*get_eeprom_len)(struct net_device *);
	int	(*get_eeprom)(struct net_device *,
			      struct ethtool_eeprom *, u8 *);
	int	(*set_eeprom)(struct net_device *,
			      struct ethtool_eeprom *, u8 *);
	int	(*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
	int	(*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
	void	(*get_ringparam)(struct net_device *,
				 struct ethtool_ringparam *);
	int	(*set_ringparam)(struct net_device *,
				 struct ethtool_ringparam *);
	void	(*get_pauseparam)(struct net_device *,
				  struct ethtool_pauseparam*);
	int	(*set_pauseparam)(struct net_device *,
				  struct ethtool_pauseparam*);
	void	(*self_test)(struct net_device *, struct ethtool_test *, u64 *);
	void	(*get_strings)(struct net_device *, u32 stringset, u8 *);
	int	(*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
	void	(*get_ethtool_stats)(struct net_device *,
				     struct ethtool_stats *, u64 *);
	int	(*begin)(struct net_device *);
	void	(*complete)(struct net_device *);
	u32	(*get_priv_flags)(struct net_device *);
	int	(*set_priv_flags)(struct net_device *, u32);
	int	(*get_sset_count)(struct net_device *, int);
	int	(*get_rxnfc)(struct net_device *,
			     struct ethtool_rxnfc *, u32 *rule_locs);
	int	(*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
	int	(*flash_device)(struct net_device *, struct ethtool_flash *);
	int	(*reset)(struct net_device *, u32 *);
	u32	(*get_rxfh_key_size)(struct net_device *);
	u32	(*get_rxfh_indir_size)(struct net_device *);
	int	(*get_rxfh)(struct net_device *, u32 *indir, u8 *key,
			    u8 *hfunc);
	int	(*set_rxfh)(struct net_device *, const u32 *indir,
			    const u8 *key, const u8 hfunc);
	void	(*get_channels)(struct net_device *, struct ethtool_channels *);
	int	(*set_channels)(struct net_device *, struct ethtool_channels *);
	int	(*get_dump_flag)(struct net_device *, struct ethtool_dump *);
	int	(*get_dump_data)(struct net_device *,
				 struct ethtool_dump *, void *);
	int	(*set_dump)(struct net_device *, struct ethtool_dump *);
	int	(*get_ts_info)(struct net_device *, struct ethtool_ts_info *);
	int     (*get_module_info)(struct net_device *,
				   struct ethtool_modinfo *);
	int     (*get_module_eeprom)(struct net_device *,
				     struct ethtool_eeprom *, u8 *);
	int	(*get_eee)(struct net_device *, struct ethtool_eee *);
	int	(*set_eee)(struct net_device *, struct ethtool_eee *);
	int	(*get_tunable)(struct net_device *,
			       const struct ethtool_tunable *, void *);
	int	(*set_tunable)(struct net_device *,
			       const struct ethtool_tunable *, const void *);
	int	(*get_per_queue_coalesce)(struct net_device *, u32,
					  struct ethtool_coalesce *);
	int	(*set_per_queue_coalesce)(struct net_device *, u32,
					  struct ethtool_coalesce *);
	int	(*get_link_ksettings)(struct net_device *,
				      struct ethtool_link_ksettings *);
	int	(*set_link_ksettings)(struct net_device *,
				      const struct ethtool_link_ksettings *);
};

更多ethtool 使用方法:
https://blog.csdn.net/u011857683/article/details/83758689

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值