现象:
在uboot下运行tftp 82000000 kernel时,一直停在“Downloading: *”
分析:
在另外一台PC上测试tftp能否正常下载,运行tftp 192.168.111.6 -c get kernel,没有停顿,很快能下载下来。
根据网上搜索,可能的原因如下:
1,tftp程序处理有问题(可能性不大,不过hpa的tftp/tftpd代码很少,加打印调试也很方便)
2,服务器有防火墙ufw或者iptables等(可能性不大,如果有问题,另外一台PC应该不能访问)
3,tftp配置有问题(可能性不大,如果有问题,另外一台PC不能访问)
4,其他问题
上面1-3个可能原因基本上不可能,为了快速查找问题,只能在代码中加打印,判断成功与失败的流程在哪里不同。
tftpd.c中tftp_sendfile函数负责发送数据给客户端。在此函数中加如下打印,并在/var/log/syslog中观测打印内容。
发现失败时,recv_time会超时并跳转到sigsetjmp()处重新执行。成功时,recv_time会继续往下走,并不会跳转到sigsetjmp()处。问题在于为什么recv_time会超时。
(void)sigsetjmp(timeoutbuf, 1); r_timeout = timeout; + syslog(LOG_NOTICE, "windsome %s %d\n",__func__, __LINE__); if (send(peer, dp, size + 4, 0) != size + 4) { syslog(LOG_WARNING, "tftpd: write: %m"); goto abort; } read_ahead(file, pf->f_convert); + syslog(LOG_NOTICE, "windsome %s %d\n",__func__, __LINE__); for (;;) { n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout); + syslog(LOG_NOTICE, "windsome %s %d:n=%d\n",__func__, __LINE__, n); if (n < 0) { + syslog(LOG_WARNING, "tftpd: read(ack): %m"); goto abort; }
为了分析超时原因,想到用wireshark抓包,看看成功与失败时数据包有何不同。
成功时图片如下,注意绿色那部分协议为TFTP的那几个包。tftpd发送一个包就会收到一个回馈包。
失败时图片如下,注意绿色那块之间有些IPv4协议的碎片包,再看看碎片包的内容,2个内容组合起来刚好是成功情况下的一个包。为何会有碎片,为何包会被切?据此我猜测时mtu有问题(网卡一个包的最大字节数)。
为了证实这个问题我对pc作了ifconfig
eth0 Link encap:Ethernet HWaddr f0:de:f1:dc:9a:c4 inet addr:192.168.111.6 Bcast:255.255.255.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:576 Metric:1发现MTU为512,一般情况下MTU应该为1500,所以修改MTU为1500进行测试
然而,这种设置mtu的方式实在麻烦,并且在网络重启或dhcp重新获取ip地址后,mtu又会变回576。为了方便,我们期望mtu值保存并且一直生效。在google了之后,找到了修改的方法,需要修改2个地方,其一是/etc/network/interfaces,其二是/etc/dhcp/dhclient.conf和/etc/dhcp3/dhclient.conf。
1:interfaces的修改,在其中加入mtu设置
auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp mtu 1500 #iface eth0 inet static # mtu 1500 # address 192.168.1.63 # netmask 255.255.255.0 # network 192.168.1.0 # #broadcast 192.168.1.250 # #gateway 192.168.1.100
request subnet-mask, broadcast-address, time-offset, routers,
domain-name, domain-name-servers, domain-search, host-name,
netbios-name-servers, netbios-scope, interface-mtu,
rfc3442-classless-static-routes, ntp-servers;
变为
request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, rfc3442-classless-static-routes, ntp-servers;