抓包看到超大报文别慌,那是网卡在帮你“作弊”
前两天有个读者私信留言发了一张tcpdump截图,一脸困惑:“我的网卡明明协商的MSS是1460,怎么抓包抓到2800多字节的TCP载荷?是不是网卡坏了?”
这不是网卡坏了,而是网卡太“聪明”了。今天我们就来聊聊TSO和GRO这两个让网卡帮CPU“作弊”的技术。
一、先讲个故事:CPU的“分拣员”困境
想象一下,你是一个快递中转站的经理(CPU),每天要处理几万件快递(网络数据包)。每个快递都要你亲手拆开、分拣、打包、贴单……忙得满头大汗。
后来你招了个实习生(网卡),跟他说:“小卡,以后大包裹你帮我拆成标准小件再发出去(TSO);送来的小件你帮我拼成大包裹再拿给我(GRO)。”
这就是Offload技术的本质:把CPU的“脏活累活”卸载给网卡硬件,让专业的人做专业的事。
ps:可苦了“网卡”小兄弟了...,实习生不容易呀,找工作不容易呀。
1.1 TSO:发送端的大包拆分助手
TSO全称TCP Segmentation Offload,是发送方向的卸载技术。传统模式下,内核协议栈要把数据切成一个个MSS大小的小段,再交给网卡发送。开启TSO后:
• 内核:把几KB甚至几十KB的大块数据直接扔给网卡 • 网卡:按照MSS自动切分成小报文,加上TCP头部,再发到网络
好比你要寄一箱书,快递站小哥(CPU)本来要一本一本打包,现在你直接把整箱书扔给自动分拣机(网卡),机器自己拆成标准包裹。
1.2 GRO:接收端的拼包神器
GRO是Generic Receive Offload,接收方向的“反向操作”。网络上传来的是一个个小报文,开启GRO后:
• 网卡:把多个连续的小报文拼接成一个大段 • 内核:一次处理一大块数据,而不是被几百个小包“轰炸”
还是快递的例子:快递站把一堆小包裹自动捆成一个大箱子再送到你手上,你开箱一次就能取出所有东西,不用拆100次小包裹。
1.3 抓包看到“超规”报文?别慌
很多刚接触TSO/GRO的朋友会犯晕:用tcpdump抓包,明明协商的MSS是1460,怎么看到本机发出的包TCP length有2800?

原因很简单:tcpdump的抓包点在“内核与网卡之间”。开启TSO后,内核交给网卡的大包还没被拆分,tcpdump先“偷看”到了。同理,开启GRO后,网卡合并后的大包被内核接收前,tcpdump也看到了“合并成果”。
# 抓包看到的现象示例
# 本机发出的包,TCP length = 2800 > 1460
12:34:56.789012 IP 10.0.0.1.12345 > 10.0.0.2.80: Flags [P.], seq 1:2801, ack 1, ...这不是网卡坏了,是网卡帮你“作弊”成功了。
二、IP分片?生产环境请远离它
聊到TSO,顺便提一下IP分片。很多人搞混“TCP分段”和“IP分片”。TCP分段由TSO/网卡完成,而IP分片是网络层的“下下策”。
IP分片有个致命缺陷:只有第一个分片携带TCP头部,后续分片没有四层信息。防火墙看到后续分片,不知道是TCP还是UDP,直接当非法报文丢弃。
所以生产环境,内核协议栈默认尽量避免IP分片——要么靠路径MTU发现,要么靠TSO在发送端就切好。
三、Linux上手实操:ethtool三板斧(建议收藏噢)
说了这么多理论,咱们直接上命令。TSO/GRO是网卡驱动级别的特性,Linux下用ethtool管理。
3.1 第一步:找到你的网卡
# 推荐方法
ip link
# 或者
ifconfig -a常见网卡名:eth0、ens192、bond0等。
3.2 第二步:查看当前状态
ethtool -k eth0 | grep -E "tcp-segmentation|generic-receive"输出示例:
tcp-segmentation-offload: on
generic-receive-offload: on3.3 第三步:开启或关闭
# 开启(需要sudo)
sudo ethtool -K eth0 tso on gro on
# 关闭
sudo ethtool -K eth0 tso off gro off
# 单独操作
sudo ethtool -K eth0 tso on
sudo ethtool -K eth0 gro on3.4 第四步:验证是否生效
# 再次查看状态
ethtool -k eth0 | grep -E "tcp-segmentation|generic-receive"
# 或者用抓包实测
tcpdump -i eth0 -c 10 -n -v四、避坑指南:这几个点必须知道
⚠️ 坑1:重启就失效
ethtool配置是临时生效的,服务器重启、网卡重启(比如ifdown/ifup)后会恢复默认。要永久生效,有两种方法:
方法一:写开机自启脚本
# /etc/rc.local 或 systemd service
/sbin/ethtool -K eth0 tso on gro on方法二:修改网络配置文件(以CentOS/RHEL为例)
# 在 /etc/sysconfig/network-scripts/ifcfg-eth0 中添加
ETHTOOL_OPTS="-K eth0 tso on gro on"⚠️ 坑2:老网卡或虚拟网卡不支持
部分老旧网卡、低版本虚拟化网卡(如virtio早期版本)可能不支持。执行命令会提示:
Cannot set device feature settings: Operation not supported遇到这种情况,要么升级驱动/虚拟化环境,要么认命——关掉它。
⚠️ 坑3:抓包排障时记得关掉
如果你用tcpdump分析问题,比如怀疑对方发的包超过了MSS,记得临时关闭TSO/GRO,否则抓包数据是“作弊后”的,可能误导排查。
# 排障时临时关闭
sudo ethtool -K eth0 tso off gro off
# 排障完再开启
sudo ethtool -K eth0 tso on gro on⚠️ 坑4:生产环境改前先测试
虽然TSO/GRO默认大多开启,但某些业务(比如DPDK、某些深度包检测设备)可能要求关闭。一定先在测试环境验证,别直接上生产。
五、性能实测:能省多少CPU?
我在一台10Gbps网卡的服务器上做过对比测试(大文件传输,约10GB):
CPU占用降低了约60%,吞吐量还略有提升。这就是硬件卸载的魅力。
六、一张图总结TSO/GRO
发送端 接收端
应用层数据(大块) 应用层数据(大块)
↓ ↑
内核协议栈(几乎不做事) 内核协议栈(一次处理大块)
↓ (大包) ↑ (大包)
【抓包点】tcpdump看到大包 ←→ 【抓包点】tcpdump看到大包
↓ ↑
网卡硬件(TSO切分) 网卡硬件(GRO合并)
↓ (小包) ↑ (小包)
网络线缆 -------------------------------→写在最后
TSO和GRO是现代数据中心网络里默默无闻的“幕后英雄”。它们不像DPDK那样炫酷,但几乎每台Linux服务器都在默默享受它们带来的性能提升。
下次你再抓包看到“超大TCP报文”,别大惊小怪,那是你的网卡在帮你干活。
你在配置网卡Offload特性时遇到过什么坑?有没有因为TSO/GRO导致抓包问题排查了半天?欢迎留言区一起聊聊!
如果觉得文章对你有帮助,欢迎点赞、在看、转发给身边被网络问题困扰的朋友~
夜雨聆风