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

差不多一个月没写文章了,这期间,主要是搞一些比较复杂的问题,一直被搞,没有搞其它的东西,也就没写出什么东西来。

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

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

  1. /* This should work for both 32 and 64 bit userland. */  
  2. struct ethtool_cmd {  
  3.     __u32   cmd;  
  4.     __u32   supported;  /* Features this interface supports */  
  5.     __u32   advertising;    /* Features this interface advertises */  
  6.     __u16   speed;      /* The forced speed, 10Mb, 100Mb, gigabit */  
  7.     __u8    duplex;     /* Duplex, half or full */  
  8.     __u8    port;       /* Which connector port */  
  9.     __u8    phy_address;  
  10.     __u8    transceiver;    /* Which transceiver to use */  
  11.     __u8    autoneg;    /* Enable or disable autonegotiation */  
  12.     __u8    mdio_support;  
  13.     __u32   maxtxpkt;   /* Tx pkts before generating tx int */  
  14.     __u32   maxrxpkt;   /* Rx pkts before generating rx int */  
  15.     __u16   speed_hi;  
  16.     __u8    eth_tp_mdix;  
  17.     __u8    reserved2;  
  18.     __u32   lp_advertising; /* Features the link partner advertises */  
  19.     __u32   reserved[2];  
  20. };  

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

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

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

下面是代码:

  1. /* 
  2. 指定网速时,需要关闭自动协商吗?需要吗?不需要吗? 
  3. 千兆有半双工吗?需要吗? 
  4. -->测试发现,设置百兆、千兆时,同时开启自动协商,则会断网再连接一次。 
  5. 如果不开自动协商,则不会断网,从千兆切换到百兆时会无效,故默认自动协商 
  6. */  
  7. #include <string.h>  
  8. #include <stdlib.h>  
  9. #include <unistd.h>  
  10. #include <stdio.h>  
  11. #include <string.h>  
  12. #include <errno.h>  
  13. #include <sys/types.h>  
  14. #include <sys/ioctl.h>  
  15. #include <sys/stat.h>  
  16. #include <sys/types.h>  
  17. #include <net/if.h>  
  18.   
  19. #include <linux/ethtool.h>  
  20. #include <linux/sockios.h>  
  21.   
  22. int ethtool_mygset(const char* devname, int* speed, int* duplex, int* autoneg, int* link)  
  23. {  
  24.     struct ifreq ifr;  
  25.     int fd = 0;  
  26.     int err = -1;  
  27.   
  28.     struct ethtool_cmd ecmd;  
  29.     struct ethtool_value edata;  
  30.   
  31.     if (devname == NULL) return -2;  
  32.   
  33.     memset(&ifr, 0, sizeof(ifr));  
  34.     strcpy(ifr.ifr_name, devname);  
  35.   
  36.     fd = socket(AF_INET, SOCK_DGRAM, 0);  
  37.     printf("socket fd: %d\n", fd);  
  38.     if (fd < 0)  
  39.     {  
  40.         perror("ethtool_gset Cannot get control socket");  
  41.         return -1;  
  42.     }  
  43.   
  44.     ecmd.cmd = ETHTOOL_GSET;  
  45.     ifr.ifr_data = (caddr_t)&ecmd;  
  46.     err = ioctl(fd, SIOCETHTOOL, &ifr);  
  47.   
  48.     if (err < 0)  
  49.     {  
  50.         perror("Cannot get device settings");  
  51.         return -1;  
  52.     }  
  53.       
  54.     printf("PHY xx - %d/%s ", ecmd.speed, (ecmd.duplex == DUPLEX_FULL) ? "Full" : "Half");  
  55.     printf(" Auto-negotiation: %s ", (ecmd.autoneg == AUTONEG_DISABLE) ? "off" : "on");  
  56.   
  57.     switch (ecmd.speed) {  
  58.     case SPEED_10:  
  59.     case SPEED_100:  
  60.     case SPEED_1000:  
  61.     case SPEED_2500:  
  62.     case SPEED_10000:  
  63.         *speed = ecmd.speed;  
  64.         break;  
  65.     default:  
  66.         fprintf(stdout, "Unknown! (%i)\n", ecmd.speed);  
  67.         break;  
  68.     };  
  69.       
  70.     switch (ecmd.duplex) {  
  71.     case DUPLEX_HALF:  
  72.     case DUPLEX_FULL:  
  73.         *duplex = ecmd.duplex;  
  74.         break;  
  75.     default:  
  76.         fprintf(stdout, "Unknown! (%i)\n", ecmd.duplex);  
  77.         break;  
  78.     };  
  79.     *autoneg = ecmd.autoneg;  
  80.   
  81.     edata.cmd = ETHTOOL_GLINK;  
  82.     ifr.ifr_data = (caddr_t)&edata;  
  83.     err = ioctl(fd, SIOCETHTOOL, &ifr);  
  84.     if (err == 0)  
  85.     {  
  86.         *link = edata.data ? 1: 0;  
  87.   
  88.         printf(" %s\n", edata.data ? "Up" : "Down");  
  89.     }  
  90.     else if (errno != EOPNOTSUPP)  
  91.     {  
  92.         perror("Cannot get link status");  
  93.     }  
  94.   
  95.     close(fd);  
  96.   
  97.     return 0;  
  98. }  
  99.   
  100. int ethtool_mysset(const char* devname, int speed, int duplex, int autoneg)  
  101. {  
  102.     int speed_wanted = -1;  
  103.     int duplex_wanted = -1;  
  104.     int autoneg_wanted = AUTONEG_ENABLE;  
  105.     int advertising_wanted = -1;  
  106.       
  107.     struct ethtool_cmd ecmd;  
  108.     struct ifreq ifr;  
  109.     int fd = 0;  
  110.     int err = -1;  
  111.   
  112.     // pass args  
  113.     if (devname == NULL)  
  114.     {  
  115.         printf("devname emtpy...\n");  
  116.         return -2;  
  117.     }  
  118.     speed_wanted = speed;  
  119.     duplex_wanted = duplex;  
  120.     autoneg_wanted = autoneg;  
  121.   
  122.     strcpy(ifr.ifr_name, devname);  
  123.   
  124.     fd = socket(AF_INET, SOCK_DGRAM, 0);  
  125.     if (fd < 0) {  
  126.         perror("ethtool_sset Cannot get control socket");  
  127.         return -1;  
  128.     }  
  129.   
  130.     ecmd.cmd = ETHTOOL_GSET;  
  131.     ifr.ifr_data = (caddr_t)&ecmd;  
  132.     err = ioctl(fd, SIOCETHTOOL, &ifr);  
  133.     if (err < 0)  
  134.     {  
  135.         perror("Cannot get current device settings");  
  136.         return -1;  
  137.     }  
  138.   
  139.     if (speed_wanted != -1)  
  140.         ecmd.speed = speed_wanted;  
  141.     if (duplex_wanted != -1)  
  142.         ecmd.duplex = duplex_wanted;  
  143.     if (autoneg_wanted != -1)  
  144.         ecmd.autoneg = autoneg_wanted;  
  145.   
  146.     if ((autoneg_wanted == AUTONEG_ENABLE) && (advertising_wanted < 0))  
  147.     {  
  148.         if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)  
  149.             advertising_wanted = ADVERTISED_10baseT_Half;  
  150.         else if (speed_wanted == SPEED_10 &&  
  151.              duplex_wanted == DUPLEX_FULL)  
  152.             advertising_wanted = ADVERTISED_10baseT_Full;  
  153.         else if (speed_wanted == SPEED_100 &&  
  154.              duplex_wanted == DUPLEX_HALF)  
  155.             advertising_wanted = ADVERTISED_100baseT_Half;  
  156.         else if (speed_wanted == SPEED_100 &&  
  157.              duplex_wanted == DUPLEX_FULL)  
  158.             advertising_wanted = ADVERTISED_100baseT_Full;  
  159.         else if (speed_wanted == SPEED_1000 &&  
  160.              duplex_wanted == DUPLEX_HALF)  
  161.             advertising_wanted = ADVERTISED_1000baseT_Half;  
  162.         else if (speed_wanted == SPEED_1000 &&  
  163.              duplex_wanted == DUPLEX_FULL)  
  164.             advertising_wanted = ADVERTISED_1000baseT_Full;  
  165.         else if (speed_wanted == SPEED_2500 &&  
  166.              duplex_wanted == DUPLEX_FULL)  
  167.             advertising_wanted = ADVERTISED_2500baseX_Full;  
  168.         else if (speed_wanted == SPEED_10000 &&  
  169.              duplex_wanted == DUPLEX_FULL)  
  170.             advertising_wanted = ADVERTISED_10000baseT_Full;  
  171.         else  
  172.             advertising_wanted = 0;  
  173.     }  
  174.   
  175.     if (advertising_wanted != -1)  
  176.     {  
  177.         if (advertising_wanted == 0)  
  178.             ecmd.advertising = ecmd.supported &  
  179.                 (ADVERTISED_10baseT_Half |  
  180.                  ADVERTISED_10baseT_Full |  
  181.                  ADVERTISED_100baseT_Half |  
  182.                  ADVERTISED_100baseT_Full |  
  183.                  ADVERTISED_1000baseT_Half |  
  184.                  ADVERTISED_1000baseT_Full |  
  185.                  ADVERTISED_2500baseX_Full |  
  186.                  ADVERTISED_10000baseT_Full);  
  187.         else  
  188.             ecmd.advertising = advertising_wanted;  
  189.     }  
  190.   
  191.     ecmd.cmd = ETHTOOL_SSET;  
  192.     ifr.ifr_data = (caddr_t)&ecmd;  
  193.     err = ioctl(fd, SIOCETHTOOL, &ifr);  
  194.     if (err < 0)  
  195.         perror("Cannot set new settings");  
  196.   
  197.     if (err < 0) {  
  198.         if (speed_wanted != -1)  
  199.             fprintf(stderr, "  not setting speed\n");  
  200.         if (duplex_wanted != -1)  
  201.             fprintf(stderr, "  not setting duplex\n");  
  202.         if (autoneg_wanted != -1)  
  203.             fprintf(stderr, "  not setting autoneg\n");  
  204.     }  
  205.   
  206.     close(fd);  
  207.   
  208.     return 0;  


原文地址:http://blog.csdn.net/subfate/article/details/44746007


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值