Windows Networking 1: 明明数据包已经到达网卡,为什么我的服务器不收包?

简介: Windows Networking 1: 明明数据包已经到达网卡,为什么我的服务器不收包? 前后端收发包的问题,往往排查起来颇为费劲。本系列以网络问题排查为基础,总结排查过程和分析结果,一步一步完善对 NDIS (Network Driver Interface Specification) Framework,以及对 Qemu Virtio netkvm 驱动的分析和研究。

作者:陈鸽

Windows Networking 1: 明明数据包已经到达网卡,为什么我的服务器不收包?

前后端收发包的问题,往往排查起来颇为费劲。本系列以网络问题排查为基础,总结排查过程和分析结果,一步一步完善对 NDIS (Network Driver Interface Specification) Framework,以及对 Qemu Virtio netkvm 驱动的分析和研究。

问题

Windows Server 通过FTP上传文件,在传输过程中触发网络异常问题导致传输失败。尽管服务器网络经过一段时间后自动恢复,但是每次上传都很容易重现问题。

基本信息收集

问题描述粗看起来挺明确的,但是我们还是要理清楚具体细节问题,例如,

1.网络异常触发的条件:其他客户端通过FTP上传文件。
2.网络异常的现象:

  1. )在这台机器上ping 127.0.0.1,显示正常。此处说明Windows的TCPIP协议栈工作正常,问题发生在更底层驱动设备上。如果此处异常,一般我们考虑通过netsh.exe来reset tcpip和winsock。
  2. )这是一台经典网络主机,在问题发生的时候,内网网卡工作正常。具体来说就是,其他同内网网段机器ping这台Windows服务器正常,通过内网网卡ping内网dns正常。
  3. )问题发生的时候,这台机器尝试ping外网网卡上配置的网关不通。此处第2和第3步说明网卡驱动本身应该工作正常,问题可能在网卡或者该外网网卡所对应的NDIS Miniport,包括对应的NDIS.sys维护的NDIS_MINIPORT_BLOCK结构和网卡驱动维护的_ADAPTER结构
  4. )在尝试ping网关的时候,运行ARP -a 显示网关MAC和IP映射关系是Incomplete。说明数据包的发送已经尝试触发ARP过程,但是无法收到响应。
  5. )基于第4步,检查网卡设备(devmgmt.msc)显示状态正常,但是网卡接口(Network Connection -> NIC Properties)显示发送计数有增加,但接收计数却没有增加。这也侧面说明ARP请求发送正常,但是没有收到响应。
  6. )最后,尝试禁用启用网卡,发现问题解决。

3.根据异常现象排查,我们初步定位ARP问题,但通过arp.exe -s 去添加静态ARP信息(arp.exe -s gw.ipv4.address ee:ff:ff:ff:ff:ff),发现还是无法ping通网关,说明arp并不是主要的原因。

定位问题

为了更准确的定位问题,我们在Windows主机上以及它的宿主机上同时抓包分析。可惜的是,这次的抓包是直接打印在屏幕上,没有保留具体抓包内容。下次如果遇到类似情况,截图补上。

口述一下抓包的分析结果,添加静态ARP之后,VIF口上的抓包我们可以看到ping的ICMP Echo Request报文由vif口发送出去,并收到ICMP Echo Reply报文。

由于之前的种种测试排查,我们认为问题发生在底层驱动,由于问题现场存在,直接从NC上抓取Windows的dump分析。

技巧分享

Windows操作系统自2008 R2开始就集成了抓包能力,功能实现在NDIS.sys上,与Windows的ETW机制协同工作,为我们排查带来便利。启用的方式很简单,运行命令,

netsh trace start capture=yes

复现问题后,运行命令,

netsh trace stop

抓到的日志文件会被写在当前用户的temp目录下。当然,在运行stop命令后,Windows会把日志文件的位置打印在cmd.exe窗口中。

使用这个命令抓到的文件可以使用Microsoft Network Monitor 3.4或者Microsoft Message Analyzer打开。Wireshark暂时无法识别。

另外,额外提一句,Windows的ETW是一个比较好的排查操作系统内部组件行为的工具,Windows提供了一些既有的Scenarios和Providers,可以使用netsh trace show scenarios和netsh trace show providers来查看。有机会另写一篇文章作为补充。对于网络来说,我这边简单组合了一下ndis,tcpip,afd,winsock相关的providers,适用一般情况下对系统网络行为做一些比较深入的研究,命令如下,


netsh trace start provider={2F07E2EE-15DB-40F1-90EF-9D7BA282188A} keywords=0xffffffffffffffff level=0xff provider={E53C6823-7BB8-44BB-90DC-3F86090D48A6} keywords=0xffffffffffffffff level=0xff provider={7D44233D-3055-4B9C-BA64-0D47CA40A232} keywords=0xffffffffffffffff level=0xff provider={50B3E73C-9370-461D-BB9F-26F32D68887D} keywords=0xffffffffffffffff level=0xff provider={43D1A55C-76D6-4F7E-995C-64C711E5CAFE} keywords=0xffffffffffffffff level=0xff maxSize=500MB fileMode=circular persistent=no overwrite=yes report=yes correlation=yes traceFile=c:\NetworkTrace.etl capture=yes packettruncatebytes=128 IPv4.Address=<ipv4.address.for.filtering>

具体命令含义可以参考netsh trace capture help

Memory Dump分析

首先查看网卡Miniport状态,并无异常状态。一般如果网卡异常我们可能会看到例如Pending OID,或者Reset等General信息,可以尝试升级网卡驱动。

image.png

接下来检查send path,也就是发送情况。在老版本Windows操作系统,我们可以看mopen上的reference,原理是tcpip.sys driver每在发送的请求的时候都会增加tcpip与miniport的mopen的reference,而在网卡会在报文发送完成后,调用tcpip.sys驱动的回调函数释放reference。

image.png

在Windows Server 2008 R2之后的版本,mopen的reference不再起作用,发送的计数被记录在tcpip.sys的Provider_Rundown_Protection中,以满足在不同的CPU上处理发送请求的能力。Rundown的计数针对每个CPU,通过加减法计算有没有pending NBL未发送。

参考资料:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-exinitializerundownprotection

通过其他状态计数来确认发送接收情况:通过code review,我们找到了Virtio netkvm的统计信息,进一步确认发送正常,接收异常。

image.png

进一步看数据结构, NetReceiveBuffer List里面是空的,NetNofReceiveBuffers 也是0,应该是网卡驱动发现没有可用的buffer,导致就不能继续收包。这里面netkvm驱动有很多做法,比如在buffer满的情况下disbale网卡中断,也就不会有收报的行为发生。

image.png

后续检查ParaNdis_ProcessRxPath函数和 virtqueue_get_buf 函数,确认ring buffer满,

image.png

根据Virtio netkvm的代码,NetReceiveBuffersWaiting这个LIST_ENTRY数据结构里面的buffer内容其实是Windows 操作系统的NDIS 框架驱动负责维护,并调用netkvm驱动注册好的 ReturnPacketHandler 也就是 netkvm!ParaNdis5_ReturnPacket 来释放buffer并放回NetReceiveBuffers中。

在这里,问题集中在为什么NDIS没有调用我们的回调函数。Windows对网卡相关的缓存回收主要依靠NET_BUFFER_LIST数据结构的Reference,也就是引用计数。如果buffer被使用,那么它的reference count就会+1,如果buffer操作完成,对应引用的驱动会调用Dereference来释放引用。只有当buffer的reference计数变为0,才会回调释放buffer函数。

问题的定位是通过枚举所有未释放的buffer,打印出网络包结构,例如,

!list "-t \_LIST\_ENTRY.Flink -e -x \"dt netkvm!IONetDescriptor @$extret; dt ndis!_NDIS_PACKET poi(@$extret+0x40) Private.; dt _MDL poi(poi(@$extret+0x40)+8); db poi(poi(poi(@$extret+0x40)+8)+0x18) L0x50\" 0xfffffadf`37fa26d0"

image.png

注:0x0bda = 3034 是FTP Pasv模式的data port。

本案例是Serv-U FTP服务器不处理收包导致buffer被用满,而通过使用Windows build-in的IIS FTP解决。

总结

综合前面的分析,一般情况下的下一步计划类似如下,

  1. Windows 本身NDIS驱动没有正确处理buffer的释放,对此,建议是安装好最新的 ndis.sys 补丁。
  2. 其他三方驱动对buffer有不正确的引用,导致引用计数一直无法为0,得到释放。建议是卸载三方,保持一个干净的操作系统。
  3. 报文没有被处理。
  • Possible Cause 1,数据包收到后需要通过消息通知机制indicate给上层Application,这里indication慢或者死锁会导致问题。
  • Possible Cause 2, 应用程序有Critical Section,导致没有recv操作发生等等。这中间就涉及了tcpip.sys, afd.sys, winsock, 以及应用程序本身,任何一环出问题都有可能引起网络问题。

对此,一般的建议是升级驱动tcpip.sys, afd.sys, 和 winsock组件,以及使用其他软件来替代当前使用的应用程序。

相关文章
|
5天前
|
Java 关系型数据库 MySQL
保姆级教程——将springboot项目部署到阿里云服务器包含环境配置(小白包会)
本文档详细介绍了将SpringBoot项目部署到阿里云服务器的步骤。首先,通过Xshell连接服务器,使用公网IP地址。接着,下载JDK的Linux版本,使用XFTP上传并解压,配置环境变量。然后,安装MySQL 5.7,包括下载YUM源、安装、启动服务以及修改root密码和开启远程访问。最后,将SpringBoot项目打包成jar,上传至服务器,使用`java -jar`命令运行,通过`nohup`确保服务持续运行。配置安全组以允许远程访问。
|
5天前
|
存储 Linux 网络安全
都2023年了还不了解?使用FileZilla搭建信息文件服务器(Windows7)
都2023年了还不了解?使用FileZilla搭建信息文件服务器(Windows7)
|
5天前
|
安全 网络协议 网络安全
在Windows7搭建FTP服务器详细教学
在Windows7搭建FTP服务器详细教学
|
6天前
|
安全 Linux 网络安全
Windows搭建Emby媒体库服务器,无公网IP远程访问本地影音文件
Windows搭建Emby媒体库服务器,无公网IP远程访问本地影音文件
16 0
|
6天前
|
安全 Linux 数据库
windows服务器 cwRsyncServer 搭建步骤
windows服务器 cwRsyncServer 搭建步骤
19 0
windows服务器 cwRsyncServer 搭建步骤
|
12天前
|
Java
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
如何解决使用若依前后端分离打包部署到服务器上后主包无法找到从包中的文件的问题?如何在 Java 代码中访问 jar 包中的资源文件?
49 0
|
12天前
|
Apache 项目管理 数据安全/隐私保护
Windows安装TortoiseSVN客户端结合Cpolar实现公网提交文件到本地服务器
Windows安装TortoiseSVN客户端结合Cpolar实现公网提交文件到本地服务器
|
14天前
|
网络协议 Windows
Windows Server 各版本搭建 DNS 服务器实现域名正反向解析
Windows Server 各版本搭建 DNS 服务器实现域名正反向解析
|
Ubuntu Linux 数据库
阿里云服务器ECS操作系统:linux系统与windows系统的区别
阿里云服务器ECS操作系统:linux系统与windows系统的区别.首先,我们要清楚的便是每个系统之间的差别,以及在阿里云上的差别
13144 0
|
3天前
|
弹性计算 运维 监控
解密阿里云弹性计算:探索云服务器ECS的核心功能
阿里云ECS是核心计算服务,提供弹性云服务器资源,支持实例按需配置、集群管理和监控,集成安全防护,确保服务稳定、安全,助力高效业务运营。
29 0