1. 问题简介

多台公设备重启过程中出现网络无法使用问题,使用ifconfig查看网络节点此时没有收到任何包,并且重启机器也存在无法恢复问题。

图1.1 异常后ifconfig信息

2. 排查过程

  • 查看中断

在PC中使用ping命令查看设备是否有反应,此时可以看到RJ45的数据灯在闪烁,说明此时是有数据进入的,通过查看 cat /proc/interrupts没有看到网络中断。

图2.1 PC ping 设备

图2.2 网络中断

经过了解该问题之前就存在,解决办法是通过将eth0节点先down掉然后在up起来,出现问题后使用该方法进行测试,测试结果如下图所示,从下图可以看到第一次对eth0重启没有恢复,第二次时才恢复正常。从这点我们可以知道两三个信息,

1)重启eth0不一定能恢复网络。

2)重启eth0概率性可恢复,恢复后有提示。

3)重启eth0 实际是对MAC进行操作,说明问题可能出现在MAC。

图2.3 重启eth0 恢复网络

  • 查看提示信息

通过错误提示找到其代码所在位置。打印在./net/netfilter/nf_conntrack_helper.c:215中,如下图所示,直接看代码不太能够理解其含义,首先需要知道一个整体的概念,不能钻到代码里面去,否则很容易不知道要干啥。

图2.4 错误打印代码位置

从打印中可以看到两个关键词iptables和nf_conntrack,通过查阅资料可以了解到如下信息。

iptables:

netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。

nf_conntrack:

nf_conntrack(在老版本的 Linux 内核中叫 ip_conntrack)是一个内核模块,用于跟踪一个连接的状态的。连接状态跟踪可以供其他模块使用,最常见的两个使用场景是 iptables 的 nat 的 state 模块。

了解到了如上信息知道这个是防火墙的以及跟踪连接状态的,首先想起是否是由于这个防火墙将数据包给隔离了,所以通过配置的方式关闭了,iptables和nf_conntrack结果发现并没有用,网络还是存在异常。说明问题不在这部分。

  • RXERR 问题

经过了解,最早该问题已经定位到了是RXERR的问题,RMII接口本身是不需要RXERR引脚,但NUC970的MAC的RXERR引脚不接入就会导致设备无法使用,具体原因是当启动过程中该引脚异常时候,此时NUC970的RXERR会进入错误状态,将MIEN寄存器的RXEN关掉。

了解到这里知道读取相关寄存器地址,MAC0基地址EMACn_BA = 0xB0002000,

EMACn_MIEN = EMACn_BA + 0x0AC = 0xB00020AC, 使用devmem读取寄存器值,具体如下:

#异常时
$devmem 0xB00020AC
0x01258C10
$devmem 0xB00020b0
0x00800610
#恢复正常后
$devmem 0xB00020AC
0x01258C11
devmem 0xB00020b0
0x00800000

通过对比正常和异常的差异点,发现0xB00020AC的bit0在异常时候为0,该位描述如下,该位是控制接收中断使能的,若该位置0了则CPU将不会受到RX中断,由此可以和上面对应上,MAC0没有任何中断的原因就是因为RXIEN没有使能导致的。

接收中断启用控制RXIEN控制RX中断的产生。如果启用RXIEN,且RXINTR (EMACn_MISTA[0])值高,则EMAC对CPU产生RX中断。如果关闭RXIEN,即使设置任何状态位EMACn_MISTA[15:1],并使能相应的EMACn_MIEN,也不会对CPU产生RX中断。换句话说,如果S/W想从EMAC接收RX中断,这个位必须是启用。并且,如果S/W不想从EMAC接收任何RX中断,禁用此功能一些。

0 = RXINTR (EMACn_MISTA[0])被屏蔽,RX中断生成被禁用。1 = RXINTR (EMACn_MISTA[0]) is not mask and RX interrupt generation Enabled。

图2.5 RXIEN寄存器描述

基于上面我们尝试在异常的时候对RXIEN位使能,操作如下所示,当将该位置1后,此时网络恢复,使用ping命令可正常与PC通讯。说明问题就在这里。

$devmem 0xB00020AC w 0x01258C11

图2.6 开启RX中断使能后网络恢复

到这里需要就有三个问题需要考虑。具体如下:

  • 什么情况下RXIEN会被禁止

  • 为什么通过down和up重启eth0不一定有用。

  • 若默认将RXIEN一直开启是否会影响网络

带着这三个问题开始排查,首先查看新塘驱动看到3处和RXIEN相关的,分别是

    a. 使能mac 中断

该函数是在open ether的时候开启的,用于打开MAC中断。

static void nuc970_enable_mac_interrupt(struct net_device *dev)
{unsigned int val;val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP | ENRDU;val |= ENTXBERR | ENRXBERR | ENTXABT | ENWOL;__raw_writel(val,  REG_MIEN);
}

   b. RX中断处理函数

该函数中收到RX中断后会关闭RX中断,然后调用napi_schedule触发poll方法,然后再poll方法中处理网络数据,这样做的目的是减少硬件中断,避免消耗CPU资源。因为中断很多会使CPU一直陷入硬中断而没有时间处理别的事情。

static irqreturn_t nuc970_rx_interrupt(int irq, void *dev_id)
{struct net_device *dev = (struct net_device *)dev_id;struct nuc970_ether *ether = netdev_priv(dev);unsigned int status;struct platform_device *pdev = ether->pdev;nuc970_get_and_clear_int(dev, &status, 0xFFFF);dev_err(&pdev->dev, "zhuajian %s +%d status = 0x%x \n",__FUNCTION__, __LINE__, status);if (unlikely(status & MISTA_RXBERR)) {dev_err(&pdev->dev, "emc rx bus error\n");nuc970_reset_mac(dev, 1);} else {if(status & MISTA_WOL) {}if(status & MISTA_RXGD) {__raw_writel(__raw_readl(REG_MIEN) & ~ENRXINTR,  REG_MIEN);napi_schedule(&ether->napi);}}return IRQ_HANDLED;
}

    c. nuc970 poll函数

网络数据接收,当数据接收完成或处理时间超了后会重新开启中断。

static int nuc970_poll(struct napi_struct *napi, int budget)
{int rx_cnt = 0;int complete = 0;struct platform_device *pdev = ether->pdev;rxbd = (ether->rdesc + ether->cur_rx);dev_err(&pdev->dev, "zhuajian %s +%d budget = 0x%x rx_cnt = 0x%x \n",__FUNCTION__, __LINE__, budget, rx_cnt);while(rx_cnt < budget) {if((rxbd->sl & RX_OWEN_DMA) == RX_OWEN_DMA) {complete = 1;break;}.......wmb();  // This is dummy function for ARM9rxbd->sl = RX_OWEN_DMA;if (++ether->cur_rx >= RX_DESC_SIZE)ether->cur_rx = 0;rxbd = (ether->rdesc + ether->cur_rx);}.......if(complete) {napi_complete(napi); //changed from __napi_complete(napi); by tanshi li for ifconfig eth0 down error__raw_writel(__raw_readl(REG_MIEN) | ENRXINTR,  REG_MIEN);}rx_out:ETH_TRIGGER_RX;return(rx_cnt);
}

通过在三个函数中增加打印,发现异常时候进入了nuc970_rx_interrupt但是没有进入到poll中,也就是在nuc970_rx_interrupt关闭了中断,但由于没有进入到poll中所以无法重新开启中断,导致后续网络都是异常的。

图2.7 打印输出

所以这里就要看为什么没有调用到nuc970_poll,理论上在nuc970_rx_interrupt中断中调用napi_schedule就会调用到nuc970_poll,所以现在就要看在什么情况下napi_schedule不会调用nuc970_poll。

napi_schedule实际调用napi_schedule_prep判断该poll是否可被调度,经过测试发现异常时候就是在该函数返回异常,导致poll方法无法被调度,napi_schedule_prep的函数如下,主要是检测两个方面:

1、是否poll已经在调度

2、是否禁止了napi pending

/***  napi_schedule_prep - check if napi can be scheduled*  @n: napi context** Test if NAPI routine is already running, and if not mark* it as running.  This is used as a condition variable* insure only one NAPI poll instance runs.  We also make* sure there is no pending NAPI disable.*/
static inline bool napi_schedule_prep(struct napi_struct *n)
{return !napi_disable_pending(n) &&!test_and_set_bit(NAPI_STATE_SCHED, &n->state);
}

增加打印发现问题出在test_and_set_bit这里说明此时有其他poll方法被调度了,说明此时NAPI的状态中NAPI_STATE_SCHED位已经被设置。继续查看代码可以发现在eth0驱动加载时候会调用netif_napi_add,将poll增加到队列中。该函数就会设置状态为NAPI_STATE_SCHED,具体代码如下所示:


static int nuc970_ether_probe(struct platform_device *pdev)
{....//增加napi 。netif_napi_add(dev, &ether->napi, nuc970_poll, /*16*/32);ether_setup(dev);if((error = nuc970_mii_setup(dev)) < 0) {dev_err(&pdev->dev, "nuc970_mii_setup err\n");goto err2;}error = register_netdev(dev);if (error != 0) {dev_err(&pdev->dev, "register_netdev() failed\n");error = -ENODEV;goto err2;}return 0;....

而在open函数中会调用napi_enable函数将NAPI_STATE_SCHED状态清除,这样做的目的是为了在驱动加载时候不工作,仅在用户ifconfig  up了网络节点时才正常工作。

通过上面的描述和代码走读,绘制代码逻辑图如下:

图2.8 驱动加载流程

图2.9 网络数据处理简化流程

通过走读代码发现问题出现在了open函数,由上可知在初始化时候调用了netif_napi_add,此时napi的状态是NAPI_STATE_SCHED,此时若有网络数据进来,则此时会触发RX中断,在中断中会关闭RX中断,且判断poll是否可被调度,此时判断状态为NAPI_STATE_SCHED,就不会调用到nuc970_poll,也就无法再开启网络中断。

那为什么open的时候回导致进入中断了,查看open的代码如下,发现在nuc970_reset_mac 和nuc970_enable_mac_interrupt中都会开启RX使能,并且在reset_mac的时候会初始化rx中断,而前面也说了清除NAPI_STATE_SCHED是在open函数的napi_enable调用中做的,若还未调用到napi_enable就有数据来了,此时就会出现上一段所描述的场景。

static int nuc970_ether_open(struct net_device *dev)
{struct nuc970_ether *ether;struct platform_device *pdev;ether = netdev_priv(dev);pdev = ether->pdev;nuc970_reset_mac(dev, 0);nuc970_set_fifo_threshold(dev);nuc970_set_curdest(dev);nuc970_enable_cam(dev);nuc970_enable_cam_command(dev);nuc970_enable_mac_interrupt(dev);nuc970_set_global_maccmd(dev);ETH_ENABLE_RX;if (request_irq(ether->txirq, nuc970_tx_interrupt,0x0, pdev->name, dev)) {dev_err(&pdev->dev, "register irq tx failed\n");return -EAGAIN;}if (request_irq(ether->rxirq, nuc970_rx_interrupt,IRQF_NO_SUSPEND, pdev->name, dev)) {dev_err(&pdev->dev, "register irq rx failed\n");free_irq(ether->txirq, dev);return -EAGAIN;}phy_start(ether->phy_dev);netif_start_queue(dev);napi_enable(&ether->napi);ETH_TRIGGER_RX;dev_info(&pdev->dev, "%s is OPENED\n", dev->name);return 0;
}

到这里根本原因已经非常清除了。就是新塘网络驱动的逻辑缺陷导致的。包括上面的三个问题也非常清楚了。

1、什么情况下RXIEN会被禁止

中断来的时候就会被静止掉,这样做的目的是减少系统频繁处理中断,而导致无法去做其他事情。内核采用NAPI技术,当中断来时开启软中断,通过轮训的方式处理数据。

2、为什么通过down和up重启eth0不一定有用。

在ifconfig eth0 up的时候调用的就是nuc970_open函数,若此时网络中有数据,例如有广播包的转发时候,此时就会出现关闭掉中断且不会调用到poll处理数据函数内。

3、若默认将RXIEN一直开启是否会影响网络

会,若大量网络数据过来会导致CPU去处理中断而无法去处理数据。非常影响性能。

3. 问题验证:

将nuc970_open函数中的不必要初始化去掉,并且将nuc970_reset_mac函数中的RX使能给去掉,将RX使能部分移动到napi_enable之后,修改后的代码如下:

图3.1 修复后的代码

修改后运行测试代码,测试代码思路是通过ping命令去ping网关,若成功则进行重启,若ping失败则不进行重启。此时就会卡住。当我们拷机测试出现设备部重启时就说明网络异常。

测试拿了两台设备,一台是最新的带PHY版本,一台是老的不带PHY版本,经过一天的测试网络数据均正常。每次都能够ping通,说明此时网络问题已修复。

带宽测试

为了节约成本,这里测试两个版本的带宽和稳定性。通过在局域网下使用iperf3工具进行带宽测试,测试结果如下:

从测试结果看两者无任何差异,说明从带宽的角度两者并没有差异。若在抗干扰能力都一样的情况下,可以使用不带PHY的版本。

4. 总结

此次排查过程了解了nuc970网络数据处理过程,同时也学习了NAPI的处理逻辑,对后续还是有非常大的帮助,同时也说明新塘SDK还是有缺陷的,后续使用过程中需要做好测试工作,将问题在产品开发阶段就暴露出来,避免问题产品流出。

nuc970 网络问题排查过程相关推荐

  1. 访问windows 共享提示找不到网络路径 排查过程

    阅读原文请点击 摘要: windows共享访问提示 "0x80070035 找不到网络路径" 网络服务异常,抓包可以一针见血看清过程 问题现象 windows 2008 系统搭建的 ...

  2. Linux网络包接收过程的监控与调优

    Linux内核对网络包的接收过程大致可以分为接收到RingBuffer.硬中断处理.ksoftirqd软中断处理几个过程.其中在ksoftirqd软中断处理中,把数据包从RingBuffer中摘下来, ...

  3. 多队列 部分队列没有包_记一次TCP全队列溢出问题排查过程

    简介:记一次TCP全队列溢出问题排查过程 1. 前言 本文排查的问题是经典的TCP队列溢出问题,因TCP队列问题在操作系统层面没有明显的指标异常,容易被忽略,故把排查过程分享给大家. 2. 问题描述 ...

  4. 一次堆外OOM问题的排查过程

    转载自   一次堆外OOM问题的排查过程 背景 线上服务有一台机器访问不通(一个管理平台),在公司的服务治理平台上查看服务的状况是正常的,说明进程还在.进程并没有完全crash掉.去线上查看机器日志, ...

  5. 记一次线上服务假死排查过程

    大家好,我是烤鸭: 最近线上问题有点多啊,分享一个服务假死的排查过程. 问题描述 9点10分,收到进程无响应报警(一共6台机器,有1台出现),后来又有1台出现. 排查思路 首先确认是否误报或者网络抖动 ...

  6. 记一次线上cpu飙升100%的排查过程

    大家好,我是烤鸭: 最近没怎么写技术文章,还是得回归下初心,正好前几天出现个线上问题,记录下排查过程. 问题描述 某个时间点,接收到接口响应慢报警. 过一会收到服务器cpu可用率低(<10%)报 ...

  7. 多次执行sql 后卡住_解Bug之路记一次中间件导致的慢SQL排查过程

    解Bug之路-记一次中间件导致的慢SQL排查过程 前言 最近发现线上出现一个奇葩的问题,这问题让笔者定位了好长时间,期间排查问题的过程还是挺有意思的,就以此为素材写出了本篇文章. Bug现场 我们的分 ...

  8. Linux网络协议栈:网络包接收过程

    目录 一 Linux网络收包总览 二 Linux启动 2.1 创建ksoftirqd内核线程 2.2 网络子系统初始化 2.3 协议栈注册 2.4 网卡驱动初始化 2.5 启动网卡 三 迎接数据的到来 ...

  9. Mysql disk write 高_优化系列|实例解析MySQL性能瓶颈排查定位 导读 排查过程

    导读 从一个现场说起,全程解析如何定位性能瓶颈. 排查过程 收到线上某业务后端的MySQL实例负载比较高的告警信息,于是登入服务器检查确认. 1. 首先我们进行OS层面的检查确认 登入服务器后,我们的 ...

最新文章

  1. 八个防止浪费时间的小窍门
  2. pta简单实现x的n次方_PTA-2017实验2.4 函数
  3. Spring Security 基本介绍,初窥路径
  4. docker java mysql_Docker 搭建 MySQL 服务
  5. mysql+默认值+default_十六、MySQL 中数据类型的默认值 - default 约束-搜云库
  6. java使用document解析xml文件
  7. vue显示服务器目录,vue-cli 静态资源在另一台服务器上.要如何配置路径
  8. acdsee免费版跳过注册账户_加快Win 10启动速度,直接跳过锁屏登录界面
  9. 222Beta多样性限制性排序CPCoA/CCA/RDA/LDA
  10. 多元线性回归分析spss结果解读_SPSS 多元线性回归结果重要参数解读
  11. DSP-28027笔记
  12. 关于计算机体系结构-北桥和南桥
  13. 有个程序媛上司是什么体验
  14. Git Clone时报错解决方法
  15. 介绍DOTA2 AI的开发基础——调试
  16. 哔哩哔哩2020校园招聘游戏测试笔试卷(二)知识点解析
  17. SQLZOO(SQL语句练习)
  18. 转大型分布式网站术语浅析
  19. wParam和lParam参数
  20. powershell基础脚本编写实例

热门文章

  1. java写作教程_如何编写技术教程-发布关于开发人员写作的新书
  2. 蚂蚁金服智能推荐引擎解决方案与实践 1
  3. Springboot+mysql+基于VUE框架的商城综合项目设计与实现 毕业设计-附源码111612
  4. 百度云推送-----10101错误
  5. 聊一聊Vector与Stack
  6. 批处理将生词导入金山词霸生词本!
  7. 学习Linux是存在捷径的
  8. Google Maps嵌入参数
  9. java-jar启动jar包
  10. 寻找假币问题(二分法)