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

在找问题过程中,上网了解到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 */__u8    duplex;     /* Duplex, half or full */__u8  port;       /* Which connector port */__u8  phy_address;__u8    transceiver;    /* Which transceiver to use */__u8  autoneg;    /* Enable or disable autonegotiation */__u8 mdio_support;__u32  maxtxpkt;   /* Tx pkts before generating tx int */__u32 maxrxpkt;   /* Rx pkts before generating rx int */__u16 speed_hi;__u8   eth_tp_mdix;__u8    reserved2;__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 argsif (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;elseadvertising_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);elseecmd.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结构体。

李迟,2015.3.28,周六早上睡不着起来写的



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

  1. linux c 获取网卡状态(UP or DOWN)

    linux c 获取网卡状态(UP or DOWN) 源代码例如以下: #include <sys/socket.h> #include <sys/ioctl.h> #incl ...

  2. 不写一段代码来获取扇贝单词的接口数据

    不写一段代码来获取扇贝单词的接口数据 第一步,登录并寻找可以爬取的数据(想直接看结论可以到第四步) 第二步,对症下药 第三步,解密接口 第四步,使用现成的方法获取数据 最近想做一个背单词相关的app, ...

  3. Linux下获取网卡名称的3种方法

    在Linux中获取网卡名称的方法如下几种,1和2两种没办法在网卡未分配IP 地址时获取: 1.采用socket方式获取网卡列表 int EthManager::listInterface() {   ...

  4. Linux 设置双网卡通信,外网网卡和内网网卡

    文章目录 Linux 设置双网卡通信,外网网卡和内网网卡 1.配置路由表 2.设置启动自动生效 Linux 设置双网卡通信,外网网卡和内网网卡 1.配置路由表 背景,Linux 主机已经安装了内网.外 ...

  5. linux如何获取网卡计数信息,Linux下如何获取网卡信息

    有时候,写程序的时候需要获取计算机的网络信息,比如IP地址.电脑名称.DNS等信息.IP地址和电脑名称是比较容易获取到的,而要想获取地址掩码.DNS.网关等信息就有些麻烦了. 在Windows下我们一 ...

  6. linux qt获取网卡mac地址,QT实战获取主机名QT获取IP地址 获取MAC地址 获取广播地址...

    QT的网络东西也蛮多的,我们今天先学一部分,然后后面在学一部分吧 一个能使用网络的应用,我们需要在项目工程中的pro文件里进行标记QT += core gui #标记 网络 QT += network ...

  7. Linux设置一个网卡IP地址,linux下一块网卡设置多个ip地址(示例代码)

    无论是在实际的生产坏境中,还是平时的练习中, 一个网卡设置多个ip地址是非常常见的,也是非常有用的. 我们以centos6.8系统为列, 在一块网卡上设置多个ip地址. 1>. 给一块网卡设置多 ...

  8. linux设置为adhoc模式,Linux下两台笔记本电脑adhoc模式搭建局域网跟adhoc无线自组织网络...

    1,准备工作 两台电脑无线网卡均配置成adhoc模式,选择信道6,ESSID为long. (信道6是我电脑旁边无线路由器所在的信道,不清楚它是否会对无线路由信号产生干扰,当然目前我把无线路由器电源拔了 ...

  9. Linux:bond网卡模式配置

    目录 一.bond概念 二.linux有七种网卡绑定模式: 三.bound配置 1.关闭防火墙.关闭核心防护 2.先添加一块网卡 3.配置网卡ens33.ens37 4.创建并配置bond0网卡信息 ...

最新文章

  1. 基于K8S构建企业级Jenkins CI/CD平台实战(一) 之 环境搭建
  2. 微信公众号手机无法直接下载APK文件是怎么回事
  3. OpenDataSource和OPENROWSET
  4. 【NLP】基于TF-IDF和KNN的模糊字符串匹配优化
  5. 最优化方法系列:SGD、Adam
  6. 谷歌浏览器怎么更新升级
  7. Bootstrap表单控件的尺寸
  8. Linux能ping主机,但ping不了网关以及外网,显示包全丢失解决方案
  9. matlab 二维数组转一维数组中,将二维数组映射到一维数组上
  10. asp.net学习笔记1
  11. 微机计算机继电保护原理,微机继电保护的装置构成
  12. SEO为什么一定要面面俱到?
  13. domain adaptation 领域自适应
  14. 如何做一场视频投票活动
  15. 进击ReactNative-徐如林-React源码解析
  16. 易语言删除全部空白字符
  17. XSSF实现Excel下拉和HSSF实现Excel下拉
  18. Android x86 4.4-r1 PC正式版发布
  19. 辅助驾驶事故频发,背后直指“决策安全模型”和驾驶员行为
  20. java缩放图片_java 图片缩放(2)

热门文章

  1. 产业链消息称台积电积极寻求更多长期代工订单
  2. 网络短视频内容审核趋严!短视频不得未经授权剪辑影视剧
  3. 法拉第未来宣布汉福德工厂获得最终生产使用资质
  4. 千万别让海底捞知道你的生日
  5. 罗永浩又接代言了!担任省钱顾问
  6. 小鹏NGP自动导航辅助驾驶Beta版体验:论软件,这台量产车可能是第一
  7. 滴滴网约车违规出京被罚15万 官方回应:系司乘线下协商
  8. 美团取消支付宝支付引关注,称饿了么也不支持微信支付,饿了么回应绝了
  9. 华为云的“大招”——Euler开源 Gauss开放 旨在建立云生态
  10. 苹果推出网页版Apple Music 浏览器上听音乐 这波操作有点迟?