DHCP client获取IP慢的问题分析报告
关键字 DHCP;DHCP client;获取IP慢; 问题描述 系统版本:OpenHarmony 3.2 Release 问题现象:设备网口为自动获取IP模式,通过网线接入网络进行DHCP拨号,网卡获取到IP的时间较长,大概在60~120秒才能获取到IP。 问题原因 正常机制 一般网卡
1 关键字
DHCP;DHCP client;获取IP慢;
2 问题描述
系统版本:OpenHarmony 3.2 Release
问题现象:设备网口为自动获取IP模式,通过网线接入网络进行DHCP拨号,网卡获取到IP的时间较长,大概在60~120秒
才能获取到IP。
3 问题原因
正常机制
一般网卡能够在10~15秒获取到IP地址。
异常机制
网口插上网线后需要1~2分钟的时间才获取到IP地址。
4 解决方案
OpenHarmony底座代码/foundation/communication/wifi/dhcp/services/dhcp_client/src/dhcp_socket.c文件,
修改CheckPacketIpSum函数。
在调用CheckUdpPacket返回失败后,删除sleep 500ms的处理,立即返回处理其他接收到的报文。
5 定位过程
1、定位前需要对DHCP协议以及DHCP client实现有大致的了解
首先简单了解下DHCP获取IP地址的过程。下图就是DHCP获取IP的过程,主要由4个报文交互完成设备(AP)作为
DHCP client获取IP的流程,对应的报文分别为:discovery、offer、request、ACK。
另外,在DHCP client进程收发包时,由于设备是没有IP地址的,因此在通过socket收包时要使用raw socket来接收报文。
当DHCP拨号成功之后,收包socket就切换普通的socket了。
2、DHCP client获取IP的代码流程
DHCP client的代码实现在\foundation\communication\wifi\dhcp\services\dhcp_client\目录下。
1) dhcp_ipv4.c中的StartIpv4函数就是DHCP client获取IP的主要函数。
2) DhcpRequestHandle函数主要实现DHCP报文的发送,这里调用InitSelecting函数来发送discovery报文。
DhcpResponseHandle函数主要实现socket接收到报文的处理。
3、通过wireshark抓包查看DHCP的交互
如果设备上能够进行wireshark抓包,可以很直观的看到DHCP获取IP地址的交互过程,能够比较快的看出DHCP交互的
哪个阶段有问题,再结合日志来分析具体的问题根因。
本案例中,由于设备无法对网卡进行镜像抓包,只能从头到尾分析日志来确定问题点。
4、寻找DHCP获取IP地址的异常日志
1) 先找到发送discovery报文的日志。代码中发送discovery报文的是InitSelecting函数,此函数处理流程的最后有一条日志,
记录了以下的关键信息:
> 发送discovery报文的次数g_sentPacketNum;
> 发送下一个discovery报文距离当前的间隔时间uTimeoutSec;
> 本次发送discovery报文后等待接收offer报文的超时时间g_timeoutTimestamp;
在问题日志中搜索InitSelecting这个关键字,以下为搜索结果。从日志上可以看出,discovery报文按照1s,2s,4s,
8s,16s,32s间隔进行重发。重复发送6次discovery报文共耗时大概1分钟,前5个discovery报文重发耗时约30s,
最后一次discovery报文重发超时时间间隔32s。
DHCP client一直在重复发送discovery,需要找出为什么一直没有收到offer报文。
2) 从” InitSelecting() DhcpDiscover g_sentPacketNum:0,timeoutSec:1,timestamp:868.”开始往下看日志,看是否能够找到
有异常的地方。
由日志上可以看到与代码实现一致的函数调用关系:
发送discovery报文流程
StartIpv4àDhcpRequestHandleàInitSelectingàDhcpDiscover
接收offer报文的流程
StartIpv4àDhcpResponseHandleàGetDhcpRawPacket
3) 发现日志中有”CheckUdpPacket() failed, pPacket->udp.dest:16327 error, htons:17408!”的记录。
CheckUdpPacket函数的调用流程是:
GetDhcpRawPacketàCheckPacketIpSumàCheckUdpPacket
也就是在收包流程中函数调用失败了。
日志结合代码看,CheckUdpPacket函数在检查收到的报文是否为DHCP报文时失败了,表示这里收到的报文
不是DHCP报文。前面已经提到,由于设备目前还没有获取到IP地址,是使用raw socket来收包的,如果网络
环境中有许多其他的UDP报文这里就会返回失败。
4) CheckUdpPacket返回失败后的处理是什么呢?
调用CheckUdpPacket的上一级函数是CheckPacketIpSum。由CheckPacketIpSum的实现看出在
CheckUdpPacket处理失败时,要sleep 500ms。
考虑下这里进程睡眠500ms的影响?当网络环境中有很多这类UDP的杂包时,在等待offer报文时只要
收到一个非DHCP的UDP报文,就要睡眠500ms,这样有可能使DHCP client进程无法收到预期的offer
报文,并需要多次重发discovery,DHCP获取IP的时长受到网络环境的影响。
5) 为了验证上述分析的正确性,缩短CheckPacketIpSum调用CheckUdpPacket返回失败时sleep的时长为1ms,
编译版本进行验证。结果DHCP client获取IP的速度显著提升,说明这里sleep的处理正是导致DHCP client
获取IP地址慢的原因。
6 知识分享
1、DHCP client获取IP地址的流程为二轮交互,4个报文分别为:discovery、offer、request、ACK。
2、raw socket收包会收到网卡上所有的报文。
更多推荐
所有评论(0)