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 下查询,设置网卡属性,配置的工具。
案例
下面分享用户态编程获取网卡属性。
- 获取属性个数
#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步的基础上
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步的基础上
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