tcpdump -i $link src 192.168.1.14 and port 4000 and greater 100 -v -nn

当rx-checksumming打开的时候,skb->csum里面是硬件计算的tcp checksum,但是不包括伪头。

dev_gro_receive()

{

...

/* Setup for GRO checksum validation */

switch (skb->ip_summed) {

case CHECKSUM_COMPLETE:

NAPI_GRO_CB(skb)->csum = skb->csum;

NAPI_GRO_CB(skb)->csum_valid = 1;

NAPI_GRO_CB(skb)->csum_cnt = 0;

break;

...

}

tcp4_gro_receive()被调到的时候skb_gro_checksum_validate会根据NAPI_GRO_CB(skb)->csum和伪头

(inet_gro_compute_pseudo是用来计算伪头的)算出tcp checksum。如果是0xffff,就是正确的。这时line 2733会返回0

2728 static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb,

2729                                                            __wsum psum)

2730 {

2731         if (NAPI_GRO_CB(skb)->csum_valid &&

2732             !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum)))

2733                 return 0;

2734

2735         NAPI_GRO_CB(skb)->csum = psum;

2736

2737         return __skb_gro_checksum_complete(skb);

2738 }

否则的话,__skb_gro_checksum_complete会用软件的方式计算checksum,如果用软件算出的checksum是正确的,

netdev_rx_csum_fault()会被调到,并且打印如下错误信息:

pr_err("%s: hw csum failure\n", dev ? dev->name : "<unknown>");

在kernel中打上如下patch

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f9a9067d038d..e9de4431acf6 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2725,29 +2725,57 @@ static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb,(!zero_okay || check));}+struct tcphdr2 {
+  __be16 source;
+  __be16 dest;
+};
+static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb,__wsum psum){
+  struct tcphdr2 *tcph;
+  __be16 dest;
+
+  tcph = (struct tcphdr2 *)(skb->head + skb->mac_header + 34);
+  dest = ntohs(tcph->dest);
+if (NAPI_GRO_CB(skb)->csum_valid &&
-       !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum)))
+      !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum))) {
+      if (dest == 4000)
+          pr_info("%s: return 0\n", __func__);return 0;
+  }NAPI_GRO_CB(skb)->csum = psum;
+  if (dest == 4000)
+      pr_info("%s: csum: %x\n", __func__, psum);return __skb_gro_checksum_complete(skb);}static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb){
+  struct tcphdr2 *tcph;
+  __be16 dest;
+
+  tcph = (struct tcphdr2 *)(skb->head + skb->mac_header + 34);
+  dest = ntohs(tcph->dest);
+if (NAPI_GRO_CB(skb)->csum_cnt > 0) {/* Consume a checksum from CHECKSUM_UNNECESSARY */NAPI_GRO_CB(skb)->csum_cnt--;
+      if (dest == 4000)
+          pr_info("%s: csum_cnt: %d\n", __func__,
+              NAPI_GRO_CB(skb)->csum_cnt);} else {/* Update skb for CHECKSUM_UNNECESSARY and csum_level when we* verified a new top level checksum or an encapsulated one* during GRO. This saves work if we fallback to normal path.*/__skb_incr_checksum_unnecessary(skb);
+      if (dest == 4000)
+          pr_info("%s: ip_summed: %d, csum_level: %d\n", __func__,
+              skb->ip_summed, skb->csum_level);}}diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 11101cf8693b..1c00b1c0db4f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1703,6 +1703,10 @@ int tcp_v4_rcv(struct sk_buff *skb)goto discard_it;th = (const struct tcphdr *)skb->data;
+  if (htons(th->dest) == 4000) {
+      print_hex_dump(KERN_WARNING, "tcp: ", DUMP_PREFIX_ADDRESS, 16, 1, skb->data, 20, 0);
+      print_hex_dump(KERN_WARNING, "ip : ", DUMP_PREFIX_ADDRESS, 16, 1, skb->data - 20, 20, 0);
+  }if (unlikely(th->doff < sizeof(struct tcphdr) / 4))goto bad_packet;
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index 870b0a335061..a89e1afb2861 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -295,6 +295,8 @@ int tcp_gro_complete(struct sk_buff *skb)skb->csum_start = (unsigned char *)th - skb->head;skb->csum_offset = offsetof(struct tcphdr, check);skb->ip_summed = CHECKSUM_PARTIAL;
+  if (ntohs(tcph->dest) == 4000)
+      pr_info("%s: %x\n", __func__, skb->ip_summed);skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;@@ -325,6 +327,8 @@ static int tcp4_gro_complete(struct sk_buff *skb, int thoff)th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr,iph->daddr, 0);
+  if (ntohs(tcph->dest) == 4000)
+      pr_info("%s: %x\n", __func__, th->check);skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;if (NAPI_GRO_CB(skb)->is_atomic)

就会得到下面的输出,默认目的端口号是4000:

[Tue Aug 27 13:11:37 2019] __skb_gro_checksum_validate_complete: return 0

[Tue Aug 27 13:11:37 2019] skb_gro_incr_csum_unnecessary: ip_summed: 2, csum_level: 0


[Tue Aug 27 14:01:51 2019] mlx5e_handle_rx_cqe_mpwrq: tot_len: 1500
[Tue Aug 27 14:01:51 2019] dump: 0000000062641c20: 24 8a 07 88 27 9a 24 8a 07 88 27 ca 08 00
[Tue Aug 27 14:01:51 2019] dump: 00000000794981dd: 45 00 05 dc bc 19 40 00 40 06 f5 96 c0 a8 01 0e
[Tue Aug 27 14:01:51 2019] dump: 00000000ba41b91d: c0 a8 01 0d
[Tue Aug 27 14:01:51 2019] dump: 00000000b7c4dfad: bd 2e 0f a0 a0 62 d3 19 36 db 5a 79 80 10 00 e5
[Tue Aug 27 14:01:51 2019] dump: 00000000a178fa19: 63 54 00 00
[Tue Aug 27 14:01:51 2019] mlx5e_handle_rx_cqe_mpwrq: check: 6354, skb: ffff9aec8e83f500
[Tue Aug 27 14:01:51 2019] mlx5e_handle_rx_cqe_mpwrq: csum: c576, skb: ffff9aec8e83f500
[Tue Aug 27 14:01:51 2019] __skb_gro_checksum_validate_complete: return 0
[Tue Aug 27 14:01:52 2019] skb_gro_incr_csum_unnecessary: ip_summed: 2, csum_level: 0
[Tue Aug 27 14:01:52 2019] mlx5e_handle_rx_cqe_mpwrq: tot_len: 604
[Tue Aug 27 14:01:52 2019] dump: 00000000a0b6ed62: 24 8a 07 88 27 9a 24 8a 07 88 27 ca 08 00
[Tue Aug 27 14:01:52 2019] dump: 00000000ece791ec: 45 00 02 5c bc 1a 40 00 40 06 f9 15 c0 a8 01 0e
[Tue Aug 27 14:01:52 2019] dump: 00000000d7dad77c: c0 a8 01 0d
[Tue Aug 27 14:01:52 2019] dump: 000000000d7a42ee: bd 2e 0f a0 a0 62 d8 c1 36 db 5a 79 80 18 00 e5
[Tue Aug 27 14:01:52 2019] dump: 00000000401e93d1: b5 78 00 00
[Tue Aug 27 14:01:52 2019] mlx5e_handle_rx_cqe_mpwrq: check: b578, skb: ffff9aec8e83fd00
[Tue Aug 27 14:01:52 2019] mlx5e_handle_rx_cqe_mpwrq: csum: 457a, skb: ffff9aec8e83fd00
[Tue Aug 27 14:01:52 2019] __skb_gro_checksum_validate_complete: return 0
[Tue Aug 27 14:01:52 2019] skb_gro_incr_csum_unnecessary: ip_summed: 2, csum_level: 0
[Tue Aug 27 14:01:52 2019] ip : 00000000794981dd: 45 00 08 04 bc 19 40 00 40 06 f3 6e c0 a8 01 0e
[Tue Aug 27 14:01:52 2019] ip : 00000000ba41b91d: c0 a8 01 0d
[Tue Aug 27 14:01:52 2019] tcp: 00000000b7c4dfad: bd 2e 0f a0 a0 62 d3 19 36 db 5a 79 80 18 00 e5
[Tue Aug 27 14:01:52 2019] tcp: 00000000a178fa19: 8b 62 00 00

也就验证了上面的分析。

组装好的gro skb的checksum是重新计算的:

323 static int tcp4_gro_complete(struct sk_buff *skb, int thoff)

324 {

325         const struct iphdr *iph = ip_hdr(skb);

326         struct tcphdr *th = tcp_hdr(skb);

327

328         th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr,

329                                   iph->daddr, 0);

可以打印th->check,该值和tcpdump观察到的值是一样的。但是具体作用仍未知。

GRO checksum在tcpdump中incorrect的问题相关推荐

  1. tcpdump中的Flags S 和Flags 是什么意思 ------顺便看看三次握手包

    我们用telnet发起tcp连接, 建立三次握手, 抓包来看看: xxxxxx$ sudo tcpdump -iany port 19006 -Xnlps0tcpdump: verbose outpu ...

  2. linux curl没有内容,curl在tcpdump中没有显示输出

    我正在尝试使用tcpdump诊断网络问题.我运行命令 tcpdump -i eth0 -nS host nameless.host.io 当我发出traceroute或ping命令来命中nameles ...

  3. linux 网络 指示灯 亮,Linux网络子系统中GRO的实现

    GRO (generic receive offload) GRO是在协议栈接收报文时进行减负的一种处理方式,该方式在设计上考虑了多种协议报文.主要原理是在接收端通过把多个相关的报文(比如TCP分段报 ...

  4. tcpdump源码分析——抓包原理

    本篇我们从总体看下tcpdump工具的抓包原理,通过学习了解并掌握其实现的机制,为后续进一步底层操作做准备. 1.1.1.1  如何实现 先来看看包传递过来的流程,如下图.包从网卡到内存,到内核态,最 ...

  5. tcpdump 命令快速实用参考手册

    对于 tcpdump 的使用,大部分管理员会分成两类.有一类管理员,他们熟知 tcpdump 和其中的所有标记:另一类管理员,他们仅了解基本的使用方法,剩下事情都要借助参考手册才能完成.出现这种情况的 ...

  6. tcpdump man 手册页的详细中文翻译

    出处:http://sanyk.is-programmer.com/posts/14645.html 原文地址 ========= 以下是本文档完整版本地址:http://sanyk.is-progr ...

  7. Linux GRO流程分析

    1.概述 GRO是针对报文接收方向的,是指设备链路层在接收报文处理的时候,将多个小包合并成一个大包一起上送协议栈,减少数据包在协议栈间交互的机制.可以通过ethtool -K eth0 gro on/ ...

  8. 【Linux4.1.12源码分析】协议栈gro收包之MAC层处理

    <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...

  9. tcpdump详解(转)

    原文地址 ========= 以下是本文档完整版本地址:http://sanyk.is-programmer.com/posts/14645.html (nt: 出现这一提示是为了避免一些网络蜘蛛把文 ...

最新文章

  1. 虚拟机无法上网/连接失败原因及解决方法
  2. Nginx中木马解决方法
  3. 网络协议枯燥难学?这个胖子要说No!
  4. springboot接收文件_SpringBoot2.x系列教程61--SpringBoot整合MQ之ActiveMQ实现消息传递
  5. python flask源码解析_浅谈flask源码之请求过程
  6. 使用Jolokia和JMX进行客户端服务器监视
  7. default.html文件,default.html
  8. 计算理论是研究用计算机解决,可计算性理论
  9. php中一个字符占用几个字节?
  10. Markdow简单介绍
  11. LINUX下载编译:segment.jar/net.loomchild.segment.srx.Srx2SaxParser
  12. iPhone越狱后,常见路径大全
  13. Intellij IDEA--导入导出配置
  14. Got permission denied while trying to connect to the Docker daemon socket
  15. 用户分类以及用户活跃度的衡量方法
  16. 基于java SSM框架的医院体检管理系统
  17. Linux创建用户密码修改
  18. UI设计初学者应该如何入门?
  19. 路由器网口1一直闪烁正常吗_网口1一直闪烁上不了网
  20. 最简单的单层神经网络实现鸢尾花分类

热门文章

  1. Cortex-M3 处理器内核
  2. 《Unity着色器和屏幕特效开发秘笈》—— 第3章 利用镜面反射让游戏闪耀起来...
  3. SQL判断是否为null如果为null则返回0
  4. 交换机、路由器、网关的概念,并知道各自的用途
  5. 【ceph相关】ceph基准性能测试工具
  6. 《python编程:从入门到实践》文件和异常——百万圆周率,pi_million_digits.txt
  7. 定时任务:创建静态定时任务、动态定时任务
  8. 还在担心图片的版权吗?分享11个无版权、高清、免费图片素材网站给你!
  9. 编译原理知识点总结——字母表和串(附思维导图)
  10. copy-to-clipboard 的拷贝使用