Linux下网卡phy状态检测与控制

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
简介: 最近在一个项目中,集成一个交换机芯片的时候,遇到一些麻烦,发现交换机的性能总是上不去,100M的交换机,实际交换能力只有10M。跟做硬件的同事一起,花了几周时间调试,才找到问题。原来是接到交换机芯片上的几个子系统,用的Micrel 8041PHY芯片,默认关闭了硬件流控,导致交换机无法通过流控来控制网络数据交换,结果使得其性能下降。而交换机每个端口的PHY与子系统的PHY都使用的Auto Negotiation来协商链接状态,子系统默认不支持流控,交换机也关闭了流控。

解决方法实际上很简单,就是在子系统端打开PHY的流控,其实也就是寄存器的一个位而已,
却花了我们几周时间。究其原因,都是由于大部分PHY芯片默认都打开流控,所以导致我们
一开始没怀疑到这上面,而且也没有引出交换机的控制口查看其状态。

子系统是跑的嵌入式Linux系统,所以在这几周的调试过程中,着重查看了Linux Kernel中
PHY的驱动,以及相关的一些系统调用。有些心得,记录下来。

Linux系统提供了两类ioctl系统调用SIOCETHTOOL和SIOCXMIIXXX,用于控制或者获取网卡
PHY的状态。这两类系统调用的实现取决于PHY驱动中对应ioctl的实现,一般的PHY驱动都
会实现至少其中的一类。下面以获取网卡的Link状态来说明这两类系统调用的使用。

  1. Create socket handler

由于这两类调用都要使用socket handler,我们先建立一个socket handler用于下面的系统
调用。

/--------------------------------------------------------------------------/
/**
@brief Detect eth link status from ETHTOOL API and MII reg.
@param ifname -- interface name.
@return Return true if link is up, return false if link is down,

        or return -1 if errors occur.

This function will first try to get eth link status from ETHTOOL API.
If it fails, it will try to get eth link status from MII reg.
*/
/--------------------------------------------------------------------------/
int get_netlink_status(char *ifname)
{

int skfd = -1;
int link_status;

if (ifname == NULL) {
    ifname = "eth0";
}


if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    nl_err("socket error\n");
    return -1;
}

link_status = detect_ethtool(skfd, ifname);
if (link_status < 0)
    link_status = detect_mii(skfd, ifname);

close(skfd);
return link_status;

}

  1. SIOCETHTOOL ioctl

下面是SIOCETHTOLL系统调用的用法。

/--------------------------------------------------------------------------/
/**
@brief Detect eth link status from ETHTOOL API.
@param skfd -- socket handler.
@param ifname -- interface name.
@return Return true if link is up, return false if link is down,

        or return -1 if errors occur.

*/
/--------------------------------------------------------------------------/
int detect_ethtool(int skfd, char *ifname)
{

struct ifreq ifr;
struct ethtool_value edata;

memset(&ifr, 0, sizeof(ifr));
edata.cmd = ETHTOOL_GLINK;

strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)-1);
ifr.ifr_data = (char *) &edata;

if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1) {
    nl_err("ETHTOOL_GLINK failed: %s\n", strerror(errno));
    return -1;
}

return (edata.data ? 1 : 0);

}

对应内核代码[linux/net/core/dev.c]中dev_ioctl()函数,对应的SIOCETHTOOL,又调用了
[linux/net/core/ethtool.c]中的实现,而dev_ethtool()函数,而这个函数最终又会调用
相应if驱动的ethtool_ops结构体中注册的函数来实现寄存器的操作。当然,不同的PHY驱动
对此有不同的操作,甚至有些PHY驱动根本没有注册这个结构体,这时,我们就要尝试下面
的方法了。

  1. SIOCxMIIxxx ioctl

下面是SIOCxMIIxxx系统调用的用法。
/--------------------------------------------------------------------------/
/**
@brief Detect eth link status from MII status reg.
@param skfd -- socket handler.
@param ifname -- interface name.
@return Return true if link is up, return false if link is down,

        or return -1 if errors occur.

*/
/--------------------------------------------------------------------------/
static int detect_mii(int skfd, char *ifname)
{

struct ifreq           ifr;
struct mii_ioctl_data *mii_val;


strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0) {
    fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname,
            strerror(errno));
    (void) close(skfd);
    return -1;
}

mii_val = (struct mii_ioctl_data *)(&ifr.ifr_data);
mii_val->reg_num = MII_BMSR;    

if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
    nl_err("SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
           strerror(errno));
    return -1;
}

if ((!(mii_val->val_out & BMSR_RFAULT)) &&
      (mii_val->val_out & BMSR_LSTATUS) &&
    (!(mii_val->val_out & BMSR_JCD))) {
    return 1;
} else {
    return 0;
}

}

对应内核代码[linux/net/core/dev.c]中dev_ioctl()函数,对应的SIOCxMIIxxx,又调用了
dev_ifsioc()函数,这个函数最终调用PHY驱动中注册的do_ioctl()函数来实现PHY寄存器的
读写。

相关实践学习
基于Hologres+Flink搭建GitHub实时数据大屏
通过使用Flink、Hologres构建实时数仓,并通过Hologres对接BI分析工具(以DataV为例),实现海量数据实时分析.
实时计算 Flink 实战课程
如何使用实时计算 Flink 搞定数据处理难题?实时计算 Flink 极客训练营产品、技术专家齐上阵,从开源 Flink功能介绍到实时计算 Flink 优势详解,现场实操,5天即可上手! 欢迎开通实时计算 Flink 版: https://cn.aliyun.com/product/bigdata/sc Flink Forward Asia 介绍: Flink Forward 是由 Apache 官方授权,Apache Flink Community China 支持的会议,通过参会不仅可以了解到 Flink 社区的最新动态和发展计划,还可以了解到国内外一线大厂围绕 Flink 生态的生产实践经验,是 Flink 开发者和使用者不可错过的盛会。 去年经过品牌升级后的 Flink Forward Asia 吸引了超过2000人线下参与,一举成为国内最大的 Apache 顶级项目会议。结合2020年的特殊情况,Flink Forward Asia 2020 将在12月26日以线上峰会的形式与大家见面。
相关文章
|
7月前
|
存储 监控 Linux
Linux: 检测磁盘坏块 你得会吧!
Linux: 检测磁盘坏块 你得会吧!
431 19
Linux: 检测磁盘坏块 你得会吧!
|
4月前
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
246 0
|
监控 网络协议 Linux
在Linux中,如何查看某个网卡是否连接着交换机?
在Linux中,如何查看某个网卡是否连接着交换机?
|
Linux 编译器 C语言
Linux内核对GCC版本的检测
Linux内核对GCC版本的检测
|
Ubuntu Linux
在Linux中,想修改ip,需要编辑哪个配置⽂件?修改完配置⽂件后,如何重启网卡?使配置生效?
在Linux中,想修改ip,需要编辑哪个配置⽂件?修改完配置⽂件后,如何重启网卡?使配置生效?
|
网络协议 Ubuntu Linux
在Linux中,如何将本地80端口的请求转发到8080端口,当前主机IP为192.168.16.1,其中本地网卡eth0。
在Linux中,如何将本地80端口的请求转发到8080端口,当前主机IP为192.168.16.1,其中本地网卡eth0。
|
监控 Linux
在Linux中,如何检测并修复/dev/hda5?
在Linux中,如何检测并修复/dev/hda5?
|
Ubuntu Linux 网络安全
在Linux中,能否给⼀个网卡配置多个IP? 如果能,怎么配置?
在Linux中,能否给⼀个网卡配置多个IP? 如果能,怎么配置?
|
监控 Linux
在Linux中,如何实时查看网卡流量为多少?如何查看历史网卡流量?
在Linux中,如何实时查看网卡流量为多少?如何查看历史网卡流量?