nuc970 网络问题排查过程
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(ðer->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, ðer->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(ðer->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 网络问题排查过程相关推荐
- 访问windows 共享提示找不到网络路径 排查过程
阅读原文请点击 摘要: windows共享访问提示 "0x80070035 找不到网络路径" 网络服务异常,抓包可以一针见血看清过程 问题现象 windows 2008 系统搭建的 ...
- Linux网络包接收过程的监控与调优
Linux内核对网络包的接收过程大致可以分为接收到RingBuffer.硬中断处理.ksoftirqd软中断处理几个过程.其中在ksoftirqd软中断处理中,把数据包从RingBuffer中摘下来, ...
- 多队列 部分队列没有包_记一次TCP全队列溢出问题排查过程
简介:记一次TCP全队列溢出问题排查过程 1. 前言 本文排查的问题是经典的TCP队列溢出问题,因TCP队列问题在操作系统层面没有明显的指标异常,容易被忽略,故把排查过程分享给大家. 2. 问题描述 ...
- 一次堆外OOM问题的排查过程
转载自 一次堆外OOM问题的排查过程 背景 线上服务有一台机器访问不通(一个管理平台),在公司的服务治理平台上查看服务的状况是正常的,说明进程还在.进程并没有完全crash掉.去线上查看机器日志, ...
- 记一次线上服务假死排查过程
大家好,我是烤鸭: 最近线上问题有点多啊,分享一个服务假死的排查过程. 问题描述 9点10分,收到进程无响应报警(一共6台机器,有1台出现),后来又有1台出现. 排查思路 首先确认是否误报或者网络抖动 ...
- 记一次线上cpu飙升100%的排查过程
大家好,我是烤鸭: 最近没怎么写技术文章,还是得回归下初心,正好前几天出现个线上问题,记录下排查过程. 问题描述 某个时间点,接收到接口响应慢报警. 过一会收到服务器cpu可用率低(<10%)报 ...
- 多次执行sql 后卡住_解Bug之路记一次中间件导致的慢SQL排查过程
解Bug之路-记一次中间件导致的慢SQL排查过程 前言 最近发现线上出现一个奇葩的问题,这问题让笔者定位了好长时间,期间排查问题的过程还是挺有意思的,就以此为素材写出了本篇文章. Bug现场 我们的分 ...
- Linux网络协议栈:网络包接收过程
目录 一 Linux网络收包总览 二 Linux启动 2.1 创建ksoftirqd内核线程 2.2 网络子系统初始化 2.3 协议栈注册 2.4 网卡驱动初始化 2.5 启动网卡 三 迎接数据的到来 ...
- Mysql disk write 高_优化系列|实例解析MySQL性能瓶颈排查定位
导读
排查过程
导读 从一个现场说起,全程解析如何定位性能瓶颈. 排查过程 收到线上某业务后端的MySQL实例负载比较高的告警信息,于是登入服务器检查确认. 1. 首先我们进行OS层面的检查确认 登入服务器后,我们的 ...
最新文章
- 八个防止浪费时间的小窍门
- pta简单实现x的n次方_PTA-2017实验2.4 函数
- Spring Security 基本介绍,初窥路径
- docker java mysql_Docker 搭建 MySQL 服务
- mysql+默认值+default_十六、MySQL 中数据类型的默认值 - default 约束-搜云库
- java使用document解析xml文件
- vue显示服务器目录,vue-cli 静态资源在另一台服务器上.要如何配置路径
- acdsee免费版跳过注册账户_加快Win 10启动速度,直接跳过锁屏登录界面
- 222Beta多样性限制性排序CPCoA/CCA/RDA/LDA
- 多元线性回归分析spss结果解读_SPSS 多元线性回归结果重要参数解读
- DSP-28027笔记
- 关于计算机体系结构-北桥和南桥
- 有个程序媛上司是什么体验
- Git Clone时报错解决方法
- 介绍DOTA2 AI的开发基础——调试
- 哔哩哔哩2020校园招聘游戏测试笔试卷(二)知识点解析
- SQLZOO(SQL语句练习)
- 转大型分布式网站术语浅析
- wParam和lParam参数
- powershell基础脚本编写实例