红联Linux门户
Linux帮助

参考ethtool写了个Linux设置、获取网卡模式的接口

发布时间:2016-06-02 16:05:25来源:linux网站作者:李迟

了解到ethtool这个工具十分强大,以为这个代码很复杂,而恰好领导要求我提供设置网卡信息的接口,于是下了代码,研究了一下,参考了一下,整理了一下。当然文中写的是第一个版本,要是这样的接口提供出去,其它部门的人肯定会有意见的。

Linux内核很早就已经加入ethtool相关的控制命令了(不是内核fans,不了解是哪个版本加入的),在用户空间调用ioctl函数即可。有空的话,就专门写篇关于ethtool的内核跟踪的文章。现在只需知道,在本文提到的功能中,使用ethtool的ETHTOOL_GSET可以获取网卡信息,而ETHTOOL_SSET是设置网卡信息,其它的可以查询ethtool.h这个头文件。


当中最重要的结构体是ethtool_cmd,其定义如下:

/* This should work for both 32 and 64 bit userland. */ 
struct ethtool_cmd { 
__u32   cmd; 
__u32   supported;  /* Features this interface supports */ 
__u32   advertising;/* Features this interface advertises */ 
__u16   speed;  /* The forced speed, 10Mb, 100Mb, gigabit */ 
__u8duplex; /* Duplex, half or full */ 
__u8port;   /* Which connector port */ 
__u8phy_address; 
__u8transceiver;/* Which transceiver to use */ 
__u8autoneg;/* Enable or disable autonegotiation */ 
__u8mdio_support; 
__u32   maxtxpkt;   /* Tx pkts before generating tx int */ 
__u32   maxrxpkt;   /* Rx pkts before generating rx int */ 
__u16   speed_hi; 
__u8eth_tp_mdix; 
__u8reserved2; 
__u32   lp_advertising; /* Features the link partner advertises */ 
__u32   reserved[2]; 
}; 


从上可以看到,我们最关心的如网卡速率、双工模式、自动协商等,都在此结构体中。于是,读取、设置这些信息,就不困难了。

由于涉及到网卡,ioctl用到的设备描述符是socket产生的描述符。读取网卡信息比较简单,赋值相关参数,调用ioctl,返回正确后即可读取ethtool_cmd中的对应字段,从而得到结果。

对于设置网卡,需要注意的是当使用自动协商——即不指定速率情况下,要将advertising设置成所有支持的模式,即把十兆百兆千兆全都加上。


下面是代码:

/*
指定网速时,需要关闭自动协商吗?需要吗?不需要吗?
千兆有半双工吗?需要吗?
-->测试发现,设置百兆、千兆时,同时开启自动协商,则会断网再连接一次。
如果不开自动协商,则不会断网,从千兆切换到百兆时会无效,故默认自动协商
*/ 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/ioctl.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <net/if.h> 

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

int ethtool_mygset(const char* devname, int* speed, int* duplex, int* autoneg, int* link) 

struct ifreq ifr; 
int fd = 0; 
int err = -1; 

struct ethtool_cmd ecmd; 
struct ethtool_value edata; 

if (devname == NULL) return -2; 

memset(&ifr, 0, sizeof(ifr)); 
strcpy(ifr.ifr_name, devname); 

fd = socket(AF_INET, SOCK_DGRAM, 0); 
printf("socket fd: %d\n", fd); 
if (fd < 0) 

perror("ethtool_gset Cannot get control socket"); 
return -1; 

ecmd.cmd = ETHTOOL_GSET; 
ifr.ifr_data = (caddr_t)&ecmd; 
err = ioctl(fd, SIOCETHTOOL, &ifr); 

if (err < 0) 

perror("Cannot get device settings"); 
return -1; 

printf("PHY xx - %d/%s ", ecmd.speed, (ecmd.duplex == DUPLEX_FULL) ? "Full" : "Half"); 
printf(" Auto-negotiation: %s ", (ecmd.autoneg == AUTONEG_DISABLE) ? "off" : "on"); 

switch (ecmd.speed) { 
case SPEED_10: 
case SPEED_100: 
case SPEED_1000: 
case SPEED_2500: 
case SPEED_10000: 
*speed = ecmd.speed; 
break; 
default: 
fprintf(stdout, "Unknown! (%i)\n", ecmd.speed); 
break; 
}; 

switch (ecmd.duplex) { 
case DUPLEX_HALF: 
case DUPLEX_FULL: 
*duplex = ecmd.duplex; 
break; 
default: 
fprintf(stdout, "Unknown! (%i)\n", ecmd.duplex); 
break; 
}; 
*autoneg = ecmd.autoneg; 

edata.cmd = ETHTOOL_GLINK; 
ifr.ifr_data = (caddr_t)&edata; 
err = ioctl(fd, SIOCETHTOOL, &ifr); 
if (err == 0) 

*link = edata.data ? 1: 0; 

printf(" %s\n", edata.data ? "Up" : "Down"); 

else if (errno != EOPNOTSUPP) 

perror("Cannot get link status"); 

close(fd); 

return 0; 

int ethtool_mysset(const char* devname, int speed, int duplex, int autoneg) 

int speed_wanted = -1; 
int duplex_wanted = -1; 
int autoneg_wanted = AUTONEG_ENABLE; 
int advertising_wanted = -1; 

struct ethtool_cmd ecmd; 
struct ifreq ifr; 
int fd = 0; 
int err = -1; 

// pass args 
if (devname == NULL) 

printf("devname emtpy...\n"); 
return -2; 

speed_wanted = speed; 
duplex_wanted = duplex; 
autoneg_wanted = autoneg; 

strcpy(ifr.ifr_name, devname); 

fd = socket(AF_INET, SOCK_DGRAM, 0); 
if (fd < 0) { 
perror("ethtool_sset Cannot get control socket"); 
return -1; 

ecmd.cmd = ETHTOOL_GSET; 
ifr.ifr_data = (caddr_t)&ecmd; 
err = ioctl(fd, SIOCETHTOOL, &ifr); 
if (err < 0) 

perror("Cannot get current device settings"); 
return -1; 

if (speed_wanted != -1) 
ecmd.speed = speed_wanted; 
if (duplex_wanted != -1) 
ecmd.duplex = duplex_wanted; 
if (autoneg_wanted != -1) 
ecmd.autoneg = autoneg_wanted; 

if ((autoneg_wanted == AUTONEG_ENABLE) && (advertising_wanted < 0)) 

if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF) 
advertising_wanted = ADVERTISED_10baseT_Half; 
else if (speed_wanted == SPEED_10 && 
duplex_wanted == DUPLEX_FULL) 
advertising_wanted = ADVERTISED_10baseT_Full; 
else if (speed_wanted == SPEED_100 && 
duplex_wanted == DUPLEX_HALF) 
advertising_wanted = ADVERTISED_100baseT_Half; 
else if (speed_wanted == SPEED_100 && 
duplex_wanted == DUPLEX_FULL) 
advertising_wanted = ADVERTISED_100baseT_Full; 
else if (speed_wanted == SPEED_1000 && 
duplex_wanted == DUPLEX_HALF) 
advertising_wanted = ADVERTISED_1000baseT_Half; 
else if (speed_wanted == SPEED_1000 && 
duplex_wanted == DUPLEX_FULL) 
advertising_wanted = ADVERTISED_1000baseT_Full; 
else if (speed_wanted == SPEED_2500 && 
duplex_wanted == DUPLEX_FULL) 
advertising_wanted = ADVERTISED_2500baseX_Full; 
else if (speed_wanted == SPEED_10000 && 
duplex_wanted == DUPLEX_FULL) 
advertising_wanted = ADVERTISED_10000baseT_Full; 
else 
advertising_wanted = 0; 

if (advertising_wanted != -1) 

if (advertising_wanted == 0) 
ecmd.advertising = ecmd.supported & 
(ADVERTISED_10baseT_Half | 
ADVERTISED_10baseT_Full | 
ADVERTISED_100baseT_Half | 
ADVERTISED_100baseT_Full | 
ADVERTISED_1000baseT_Half | 
ADVERTISED_1000baseT_Full | 
ADVERTISED_2500baseX_Full | 
ADVERTISED_10000baseT_Full); 
else 
ecmd.advertising = advertising_wanted; 

ecmd.cmd = ETHTOOL_SSET; 
ifr.ifr_data = (caddr_t)&ecmd; 
err = ioctl(fd, SIOCETHTOOL, &ifr); 
if (err < 0) 
perror("Cannot set new settings"); 

if (err < 0) { 
if (speed_wanted != -1) 
fprintf(stderr, "  not setting speed\n"); 
if (duplex_wanted != -1) 
fprintf(stderr, "  not setting duplex\n"); 
if (autoneg_wanted != -1) 
fprintf(stderr, "  not setting autoneg\n"); 

close(fd); 

return 0; 


本文目的是使用ethtool接口为应用程序服务器,没有深入研究其原理,也不涉及ifreq结构体。


本文永久更新地址:http://www.linuxdiyf.com/linux/21185.html