免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 12657 | 回复: 10

[网络子系统] Linux 发生RTO的段 被ACK 后是会立刻进入Open状态吗? [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
发表于 2018-06-15 20:27 |显示全部楼层
本帖最后由 goingstudy 于 2018-06-15 20:40 编辑

假设不用SACK和Timestamp选项,在发生RTO后,Linux 是把重传队列全标记为丢失:
  1. tcp_retransmit_timer()
  2.     tcp_enter_loss()
  3.         tcp_timeout_mark_lost()
复制代码
如果随后的ACK 应答了RTO的段,是会把重传队列全部恢复吗(删除重传标记,进入Open状态),这个代码是在哪里做的?
这个我用packetdrill 确认了,但是有疑问,而且没找到代码在哪里做的
  1. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
  2. +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
  3. +0.000 setsockopt(3, SOL_SOCKET, SO_SNDBUF, [131072], 4) = 0
  4. +0.000 bind(3, ..., ...) = 0
  5. +0.000 listen(3, 1) = 0

  6. +0.100 < S 0:0(0) win 40000 <mss 1000>
  7. +0.000 > S. 0:0(0) ack 1 <mss 1460>
  8. +0.100 < . 1:1(0) ack 1 win 40000
  9. +0.000 accept(3, ..., ...) = 4

  10. +0.100 write(4, ..., 10000) = 10000     ==> 发生10个段
  11. +0.100 < . 1:1(0) ack 4001 win 30000 ==> ACK 4个
  12. +0.500 %{                                         ==> 500ms,强制RTO
  13. print "ca_state:", tcpi_ca_state             ==> 4(Loss)
  14. print "reordering:", tcpi_reordering        ==> 3
  15. print "lost:", tcpi_lost                            ==> 6(重传队列全部被标记为 Loss)
  16. print "retrans:", tcpi_retrans                  ==> 1,4000-5000被重传
  17. }%
  18. +0.000 < . 1:1(0) ack 6001 win 30000   ==> Ack 6001, 这里还有个问题,为什么没有触发Reno的partial Ack后的重传?

  19. +0.100 %{
  20. print "ca_state:", tcpi_ca_state              ==> 0(立刻离开进入Open???)
  21. print "reordering:", tcpi_reordering        ==> 3
  22. print "lost:", tcpi_lost                            ==> 0(重传队列的Loss标记全部被清除,即使还有没被Ack的)
  23. print "retrans:", tcpi_retrans                  ==> 0
  24. }%


复制代码



论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
发表于 2018-06-15 20:44 |显示全部楼层
用上面的例子,当Ack6001来时,代码会
tcp_ack()
tcp_clean_rtx_queue() 会删除已经被ACK的段,但是不会全部(Loss标记应该还存在),
tcp_fastretrans_alert() 在这个函数也没有找到进入Open 状态的代码

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
发表于 2018-06-16 16:10 |显示全部楼层
明白了。
如果ACK6001,FRTO 会UNDO
如果ACK5001,那么会继续在CA_Loss。

论坛徽章:
0
发表于 2018-12-14 16:52 |显示全部楼层
进入到FRTO状态应该是DISORDER,不会是LOSS状态

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
发表于 2018-12-18 10:12 |显示全部楼层
回复 4# csg109 这是你实际做过实验得出的还是自己认为的?
上面我的列子里得出的是Open,而且从代码分析
timeout ->
tcp_enter_loss -> tp->frto = 1, LOSS

Ack6001->
snd_una_advanced
prior_fack = tp->snd_una
tcp_ack_update_window
tcp_clean_rtx_queue  --> FLAG_ORIGI_SACK_ACKED
tcp_ack_is_dubious --> tcp_fastretrans_alert -->
tcp_process_loss-->
tcp_try_undo_loss-> tcp_set_ca_state(TCP_CA_Open)

如果没问题的话,就应该是open。



论坛徽章:
0
发表于 2018-12-19 17:50 |显示全部楼层
回复 5# goingstudy
这是我打印出来的东西,加了一个snd_cwnd和packets_out
ca_state: 1
reordering: 3
lost: 0
retrans: 1
snd_cwnd: 5
packets_out: 5

ca_state: 1
reordering: 3
lost: 0
retrans: 0
snd_cwnd: 5
packets_out: 4

进入到frto,应该是tcp_retransmit_timer中这几句
if (tcp_use_frto(sk)) {
                tcp_enter_frto(sk);
        } else {
                 tcp_enter_loss(sk, 0);
        }

而调用tcp_enter_frto()后面是切换到Disorder状态.


论坛徽章:
0
发表于 2018-12-19 17:59 |显示全部楼层
回复 6# csg109

如果把ipv4目录下的tcp_frto由2变成0,那就关闭了FRTO功能,然后打印的信息ca_state: 4
reordering: 3
lost: 5
retrans: 1
snd_cwnd: 1
packets_out: 5

ca_state: 4
reordering: 3
lost: 3
retrans: 2
snd_cwnd: 2
packets_out: 3

此时是进入到loss状态,然后开始窗口为1的慢启动状态,你是什么内核版本?

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
发表于 2018-12-20 20:20 |显示全部楼层
建议你用最新的代码试试,
tcp_enter_frto这个函数都已经找不到了,而且RTO后 ca_state == 1?
还有我是在non-sack 和non-TS下做的测试

论坛徽章:
0
发表于 2018-12-21 10:37 |显示全部楼层
回复 8# goingstudy

最新的代码是先切换到LOSS状态,但是你说退回的open的路径我认为可能有误,因为你的ack 6001确认了两个数据包,一个4001 一个5001,遍历的处理4001的时候,如果数据包重传过,会给flag打上重传过的标记,处理5001包的时候,会给flag加上FLAG_ORIG_SACK_ACKED标记        if (unlikely(sacked & TCPCB_RETRANS)) {
            if (sacked & TCPCB_SACKED_RETRANS)
                tp->retrans_out -= acked_pcount;
            flag |= FLAG_RETRANS_DATA_ACKED;
        } else if (!(sacked & TCPCB_SACKED_ACKED)) {


            last_ackt = tcp_skb_timestamp_us(skb);
            WARN_ON_ONCE(last_ackt == 0);
            if (!first_ackt)
                first_ackt = last_ackt;

            last_in_flight = TCP_SKB_CB(skb)->tx.in_flight;
            if (before(start_seq, reord))
                reord = start_seq;
            if (!after(scb->end_seq, tp->high_seq))
                flag |= FLAG_ORIG_SACK_ACKED;
        }

退出循环后,如果是reno模式,会根据该ack是否含有FLAG_RETRANS_DATA_ACKED标记,把FLAG_ORIG_SACK_ACKED清除
        if (tcp_is_reno(tp)) {
            tcp_remove_reno_sacks(sk, pkts_acked);

            /* If any of the cumulatively ACKed segments was
             * retransmitted, non-SACK case cannot confirm that
             * progress was due to original transmission due to
             * lack of TCPCB_SACKED_ACKED bits even if some of
             * the packets may have been never retransmitted.
             */
            if (flag & FLAG_RETRANS_DATA_ACKED)
                flag &= ~FLAG_ORIG_SACK_ACKED;
        }

原因代码的英文注释也写的很清除了,所以之后的tcp_process_loss就会不调用你说的那个路径.


论坛徽章:
0
发表于 2018-12-21 10:44 |显示全部楼层
回复 8# goingstudy

我看下的官方的patch,1236f22fbae15,这个是前几个月加的patch,可能你用的内核还没有加这个patch,所以进切换到OPEN状态。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP