网络子系统
网络子系统在Linux内核中主要负责管理各种网络设备,并实现各种网络协议栈,最终实现通过网络连接其它系统的功能,本章节主要包含协议栈收发包流程的梳理和丢包及时延两个典型问题的分析。
网络协议栈接收发送流程
- linux 内核网络数据包接收流程

- 网络数据包(Frame)到达网卡,按照FIFO顺序存入网卡的接受队列
- 网卡通过DMA方式将接受队列的数据拷贝到内核缓冲区sk_buffer
- 当数据拷贝完成后,网卡通过硬件中断(IRQ)通知CPU有新的网络数据到来,CPU执行驱动程序(NIC Driver)的处理逻辑1 禁用网卡的中断 2 启动软中断
- 软中断处理
- TCP/IP协议层逐层处理
待内存中的所有数据包被处理完成后(即poll函数执行完成),启用网卡的硬中断,这样下次网卡再收到数据的时候就会通知CPU。
- 应用程序通过read()从套接字缓冲区读取数据
- linux 内核网络数据包发送流程

- 应用程序调用 Socket API发送网络包,套接字层把数据包放到 Socket 发送缓冲区中
- TCP/IP协议栈处理
- 协议栈处理完成后产生软中断通知驱动程序,发送队列中有新的网络帧需要发送
- 最后,驱动程序通过 DMA ,从发包队列中读出网络帧,并通过物理网卡把它发送出去
丢包问题分析
- 使用 ping 命令测试网络连接,查看是否存在丢包现象,如:
1# ping -c 5目目标 IP>
其中,-c 表示发送 ICMP 请求的次数,可以根据实际需要进行调整。如果出现丢包现象,则说明网络连接存在问题。
- 使用 ethtool 命令查看网络接口的速率、双工模式等信息,例如:
1# ethtool <网络接口>
如果网络速率不稳定或双工模式设置不正确,也会导致丢包现象。
- 使用 tcpdump 命令抓包,查看网络数据包流向和内容,如:
1# tcpdump -i <网络接口> -n -s 0 -vvv -w抓抓包文件名>
其中,-i 表示指定要抓的网络接口,-n 表示不进行 DNS 反向解析,-s 0 表示不截断数据包,-vvv 表示输出详细信息,-w 表示指定抓包文件名。抓到数据包后,可以使用 Wireshark 等工具进行分析。
- 使用 netstat 命令查看网络连接状态,例如:
1# netstat -an | grep目目标 IP>
其中,-an 表示查看所有网络连接状态,grep <目标 IP> 表示过滤指定 IP 地址的连接。通过该命令可以查看到连接状态、本地和远端端口号等信息,如果连接状态为 TIME_WAIT,则已已已经关闭,否则可能存在网络问题。
网卡或者驱动丢包
如果 ethtool -S xxx 中有 rx_xxx_errors 那么很可能是网卡有问题,可以更新到最新的驱动来验证是否解决问题。
netstat -i 也会提供每个网卡的接发报文以及丢包的情况,正常情况下输出中 error 或者 drop 应该为 0。

如果硬件或者驱动没有问题,一般网卡丢包是因为设置的缓存区(ring buffer)太小,可以使用 ethtool 命令查看和设置网卡的 ring buffer。
ethtool -g 可以查看某个网卡的 ring buffer。

Pre-set 表示网卡最大的 ring buffer 值,可以使用 ethtool -G enp125s0f3 rx 8192 设置它的值。
内核丢包
如果怀疑包在内核函数上丢失,可以使用 dropwatch 工具监听。

还可以使用 linux perf 工具监听 kfree_skb(把网络报文丢弃时会调用该函数) 事件的发生。
1# perf record -g -a -e skb:kfree_skb
2# perf script
评价此篇文章
