免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3505 | 回复: 9
打印 上一主题 下一主题

[网络子系统] tcp_retransmit_skb 函数的有关问题 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-01-04 22:19 |只看该作者 |倒序浏览
本帖最后由 jiufei19 于 2013-01-06 16:59 编辑

大家好,我在阅读tcp_retransmit_skb函数(V2.6.23版本),其中有段代码不明白其作用,希望大家能解惑

int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
   ...
      /* Some Solaris stacks overoptimize and ignore the FIN on a
       * retransmit when old data is attached.  So strip it off
       * since it is cheap to do so and saves bytes on the network.
       */

      if (skb->len > 0 &&
          (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
          tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
          /* (snd_una == end_seq - 1) 意味着当前被重传的skb是一个FIN,且是重传队列中最后一个需要重传的 */         
          if (!pskb_trim(skb, 0)) {
              TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
              skb_shinfo(skb)->gso_segs = 1;
              skb_shinfo(skb)->gso_size = 0;
              skb_shinfo(skb)->gso_type = 0;
              skb->ip_summed = CHECKSUM_NONE;
              skb->csum = 0;
          }
      }
   ...
}

我的问题就是上面绿色注释的意思不太明白,不知道和下面的具体处理有何关系,其中跟踪pskb_trim(skb, 0)这个函数可以看出实际就是将此重传skb->len置为0.

希望大家帮助!

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
2 [报告]
发表于 2013-01-06 12:05 |只看该作者
本帖最后由 瀚海书香 于 2013-01-08 13:01 编辑

回复 1# jiufei19
根据代码的解释理解就可以啊。

因为某些Solaris系统的协议栈会忽略重传带有老的数据部分(payload)的FIN,所以在重传FIN的时候,将数据部分去掉,这样也可以减少网络流量。

   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
3 [报告]
发表于 2013-01-06 16:35 |只看该作者
本帖最后由 jiufei19 于 2013-01-06 16:44 编辑

谢谢版主的提示。

的确,原文注释应该是如版主所说的那样,但是,如果这样理解,那么上面的第1个if条件中的如下判断就不好理解了。

(tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) )

这个条件如果成立,表示目前最早未确认的数据就是一个FIN,但是,现在明明这个FIN和之前某个Old数据合并在一起了,共同构成了即将被重发的分段,那么这个被重发的分段的起始序号就应该是snd_una,那么怎么可能snd_una既等于FIN的起始序号,又等于FIN之前某个数据分段的起始序号呢?

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
4 [报告]
发表于 2013-01-06 17:44 |只看该作者
回复 3# jiufei19
(tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) )

这个条件如果成立,表示目前最早未确认的数据就是一个FIN,但是,现在明明这个FIN和之前某个Old数据合并在一起了,共同构成了即将被重发的分段,那么这个被重发的分段的起始序号就应该是snd_una,那么怎么可能snd_una既等于FIN的起始序号,又等于FIN之前某个数据分段的起始序号呢?


因为没有详细看重传这块的代码,所以猜测一种可能:

最后发送的数据包是 (olddata+FIN),这个skb被放到了发送队列,等待ack。
过来一段时间,对端对olddata进行了ack,但是没有对FIN进行ack。
这个时候重传数据, snd_nua是FIN的序号,但是skb->seq是olddata的序号。


   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
5 [报告]
发表于 2013-01-07 10:17 |只看该作者
本帖最后由 jiufei19 于 2013-01-07 10:42 编辑

谢谢版主。

从代码角度来看,当 tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)条件满足时,就表示此时snd_una已经被更新为FIN的起始序号了,所以代码中的注释才有old data的说法(因为这些数据的序号位于FIN之前),那么说明此时在进行重传时,snd_una一定在另外的地方被更新过。我们知道snd_una是在tcp_ack中被更新的,并且如果更新后,会调用tcp_clean_rtx_queue,将待重传数据清除。而tcp_retransmit_skb函数是在RTO超时重传时进行的,请问版主,是否有可能在tcp_ack中刚刚更新过snd_una后,还没有来得及调用tcp_clean_rtx_queue,并reset RTO timer时,RTO超时发生,然后内核转而执行RTO处理程序,发生本帖的现象?但是,如果tcp_ack的执行不能被RTO超时处理中断的话,那么这个snd_una现象就不好理解了。

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
6 [报告]
发表于 2013-01-08 12:48 |只看该作者
怎么会发生对方确认了old data,而这些old data却并没有从重传队列中删除,以至于发送方将old data和FIN合并在一起了的现象?这究竟是什么场景才能发生的呢?

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
7 [报告]
发表于 2013-01-08 13:25 |只看该作者
回复 6# jiufei19
在看一下这个http://bbs.chinaunix.net/forum.p ... ;extra=#pid23751196的3楼。
之前描述的有问题。

   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
8 [报告]
发表于 2013-01-08 14:25 |只看该作者
本帖最后由 jiufei19 于 2013-01-08 15:40 编辑

谢谢版主!

版主的意思是在tcp的处理过程中,RTO超时处理程序是可以中断当前tcp的处理的?

我从头跟踪了下代码的执行,是从链路层的处理如process_backlog这个函数开始,直到tcp_v4_do_rcv,然后进入到tcp_rcv_established,然后再进入tcp_ack,的确没有发现有对local_bh_disable的调用,那么是否可以说RTO的超时处理程序(还是一个softirq)就可以打断tcp_ack的执行了? 但是如果可以打断tcp_ack的话,那么raise_softirq_irqoff中的那段注释又讲不通了,彻底晕了!

请斑竹解惑

论坛徽章:
0
9 [报告]
发表于 2013-01-09 13:32 |只看该作者
回复 5# jiufei19

tcp_ack会先更新snd_una, 然后调用tcp_clean_rtx_queue()来free skb, 但是它只会free fully acked skb, partially acked skb不会被free掉。所以tck_retransmit_skb会拿到最后一个data + fin的skb,如果如版主所说,receiver只ack了data的话。

但是还有一个问题就是,在tcp_retransmit_skb的前面会trim掉snd_una以前的数据,
  1.       
  2.         if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) {
  3.                 if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
  4.                         BUG();
  5.                 if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
  6.                         return -ENOMEM;
  7.         }
复制代码
所以跑到后面的话似乎也不太可能出现 tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1) && skb_len > 0的情况...

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
10 [报告]
发表于 2013-01-09 15:10 |只看该作者
是的,在tcp_tso_acked中,将调用tcp_trim_head对已确认的部分tso分段进行trim,那么残留的分段将不再包含任何已被确认的数据了,而在tcp_clean_rtx_queue中的确不对该tso模式的skb进行回收,但是这样和FIN进行合并的话,仍然想不出会有tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)的情况出现。

很奇怪!谢谢eexplorer的讨论
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP