主要涉及到两个变量,一是重传报文计数retrans_out;二是丢失报文计数lost_out。

RACK丢失报文判断

如下函数tcp_rack_detect_loss,如果报文具有丢失标志(TCPCB_LOST),但是没有重传标志(TCPCB_SACKED_RETRANS),表明丢失报文还未进行重传,不进行重复处理。否则,在RACK确认报文已经丢失之后,由函数tcp_mark_skb_lost进行丢失标记。

static void tcp_rack_detect_loss(struct sock *sk, u32 *reo_timeout)
{*reo_timeout = 0;reo_wnd = tcp_rack_reo_wnd(sk);list_for_each_entry_safe(skb, n, &tp->tsorted_sent_queue, tcp_tsorted_anchor) {struct tcp_skb_cb *scb = TCP_SKB_CB(skb);/* Skip ones marked lost but not yet retransmitted */if ((scb->sacked & TCPCB_LOST) &&!(scb->sacked & TCPCB_SACKED_RETRANS))continue;if (!tcp_rack_sent_after(tp->rack.mstamp,tcp_skb_timestamp_us(skb),tp->rack.end_seq, scb->end_seq))break;/* A packet is lost if it has not been s/acked beyond* the recent RTT plus the reordering window.*/remaining = tcp_rack_skb_timeout(tp, skb, reo_wnd);if (remaining <= 0) {tcp_mark_skb_lost(sk, skb);

在函数tcp_mark_skb_lost中,如果重传报文(标志TCPCB_SACKED_RETRANS)丢失,清除其重传标志TCPCB_SACKED_RETRANS,以便进行下一次重传。在以上tcp_rack_detect_loss丢失检测中,可见,对此种丢失未重传报文不进行重复处理。

注意,这里对重传丢失的报文,减少重传报文计数retrans_out。以下将会看到Reno在标记丢包时,不处理retrans_out计数。

void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb)
{struct tcp_sock *tp = tcp_sk(sk);tcp_skb_mark_lost_uncond_verify(tp, skb);if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;tp->retrans_out -= tcp_skb_pcount(skb);

与Reno不同,RACK(或者SACK)可标记重传队列中多个报文为丢失状态(TCPCB_LOST),Reno仅能表示重传队列首个报文。因而,在重传时,RACK(或SACK)也可重传多个丢失的报文。参见以下重传函数tcp_xmit_retransmit_queue中的判断,retrans_out不能大于lost_out,不能重传大于丢失数量的报文。

void tcp_xmit_retransmit_queue(struct sock *sk)
{rtx_head = tcp_rtx_queue_head(sk);skb = tp->retransmit_skb_hint ?: rtx_head;max_segs = tcp_tso_segs(sk, tcp_current_mss(sk));skb_rbtree_walk_from(skb) {...segs = tp->snd_cwnd - tcp_packets_in_flight(tp);if (segs <= 0) return;sacked = TCP_SKB_CB(skb)->sacked;/* In case tcp_shift_skb_data() have aggregated large skbs,* we need to make sure not sending too bigs TSO packets*/segs = min_t(int, segs, max_segs);if (tp->retrans_out >= tp->lost_out) {break; ...if (tcp_retransmit_skb(sk, skb, segs)) return;

Reno丢包计数

以下为Reno算法的丢包标记函数tcp_newreno_mark_lost,与RACK(或者SACK)不同,Reno没有足够的信息判断多个报文的丢失情况,根据重复ACK(dupack)仅能判断,SND.UNA序号开始的报文(重传队列首报文)丢失。所以,如果重传队列首个skb,包含多个报文,或者其长度大于MSS值,进行分片,TCPCB_LOST丢包标志只能设置于第一个长度不大于MSS的报文。

这里也就不需要像以上的RACK算法,或者SACK算法遍历重传队列,Reno调用tcp_skb_mark_lost_uncond_verify函数标记重传队列首报文(可能是分片后报文)丢失即可。

另外Reno与RACK/SACK的不同在于,后者在tcp_mark_skb_lost函数中检测重传报文的丢失,并且减少重传报文计数,而Reno不进行处理。Reno仅在接收到确认ACK(无论是确认原始还是重传报文)时将retrans_out减一。

void tcp_newreno_mark_lost(struct sock *sk, bool snd_una_advanced)
{        const u8 state = inet_csk(sk)->icsk_ca_state;struct tcp_sock *tp = tcp_sk(sk);if ((state < TCP_CA_Recovery && tp->sacked_out >= tp->reordering) ||(state == TCP_CA_Recovery && snd_una_advanced)) {struct sk_buff *skb = tcp_rtx_queue_head(sk);u32 mss;if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)return;mss = tcp_skb_mss(skb);if (tcp_skb_pcount(skb) > 1 && skb->len > mss)tcp_fragment(sk, TCP_FRAG_IN_RTX_QUEUE, skb,mss, mss, GFP_ATOMIC);tcp_skb_mark_lost_uncond_verify(tp, skb);

如下tcp_skb_mark_lost_uncond_verify,如果报文没有被确认丢失并且也没有被对端SACK确认接收,增加lost_out丢包计数,并且设置标志TCPCB_LOST。对于Reno而言,不可能被SACK确认,并且在以上函数tcp_newreno_mark_lost中,也已经确认了报文还没有设置TCPCB_LOST标志,所以这里的if判断必定成立。

另外,由于Reno仅标记一个报文,lost_out值递增1。而且在以上函数中判断只要首报文被设置了TCPCB_LOST标志,不继续重复标记,因而,lost_out的值实际上总是1。

void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb)
{       tcp_verify_retransmit_hint(tp, skb);tcp_sum_lost(tp, skb); if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) {tp->lost_out += tcp_skb_pcount(skb);TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;

接下来看一看Reno的丢失计数lost_out的减少。在接收到ACK确认报文后,清理重传队列函数tcp_clean_rtx_queue中,如果检测到报文设置了TCPCB_LOST标志,将丢包计数lost_out减去相应的报文数量。对于Reno而言,仅有可能在重传队列的首报文中设置TCPCB_LOST标志。由于在设置TCPCB_LOST标志时,确保了重传队列第一个skb仅包含一个报文,这里lost_out相当于递减1,其值变为0。

注意,由于被对端确认接收,此报文将由重传队列中移除,这样队列中的下一个报文(成为首报文)才有可能被标记为TCPCB_LOST,参见以上函数tcp_newreno_mark_lost。

static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack,u32 prior_snd_una, struct tcp_sacktag_state *sack)
{for (skb = skb_rb_first(&sk->tcp_rtx_queue); skb; skb = next) {struct tcp_skb_cb *scb = TCP_SKB_CB(skb);u8 sacked = scb->sacked;if (after(scb->end_seq, tp->snd_una)) {...} else {acked_pcount = tcp_skb_pcount(skb);}if (sacked & TCPCB_LOST)tp->lost_out -= acked_pcount;

Reno重传计数

在报文重传函数tcp_retransmit_skb中,重传成功之后,更新重传计数,由于在上节介绍的tcp_newreno_mark_lost函数中,将重传队列首个skb分片为单报文,此处retrans_out相当于递增1。并且为报文增加重传标志TCPCB_RETRANS。

int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
{struct tcp_sock *tp = tcp_sk(sk);int err = __tcp_retransmit_skb(sk, skb, segs);if (err == 0) {
#if FASTRETRANS_DEBUG > 0if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {net_dbg_ratelimited("retrans_out leaked\n");}
#endifTCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS;tp->retrans_out += tcp_skb_pcount(skb);

在以上函数tcp_retransmit_skb的调用函数tcp_xmit_retransmit_queue中,如果重传的报文数量retrans_out大于等于丢失报文数量lost_out,停止遍历重传队列。对于Reno,丢失报文计数lost_out为1,仅允许重传一个报文。此后,retrans_out的值也增加为1。

void tcp_xmit_retransmit_queue(struct sock *sk)
{rtx_head = tcp_rtx_queue_head(sk);skb = tp->retransmit_skb_hint ?: rtx_head;max_segs = tcp_tso_segs(sk, tcp_current_mss(sk));skb_rbtree_walk_from(skb) {...segs = tp->snd_cwnd - tcp_packets_in_flight(tp);if (segs <= 0) return;sacked = TCP_SKB_CB(skb)->sacked;/* In case tcp_shift_skb_data() have aggregated large skbs,* we need to make sure not sending too bigs TSO packets*/segs = min_t(int, segs, max_segs);if (tp->retrans_out >= tp->lost_out) {break; ...if (tcp_retransmit_skb(sk, skb, segs)) return;

在接收到ACK确认报文后,清理重传队列函数tcp_clean_rtx_queue中,如果报文设置了重传标志TCPCB_RETRANS,将retrans_out减少相应的报文数量,对于Reno而言,相当于递减1。同时在此函数中,也将丢失报文数量lost_out减去1。

static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack,u32 prior_snd_una, struct tcp_sacktag_state *sack)
{for (skb = skb_rb_first(&sk->tcp_rtx_queue); skb; skb = next) {struct tcp_skb_cb *scb = TCP_SKB_CB(skb);u8 sacked = scb->sacked;if (after(scb->end_seq, tp->snd_una)) {...} else {acked_pcount = tcp_skb_pcount(skb);}if (unlikely(sacked & TCPCB_RETRANS)) {if (sacked & TCPCB_SACKED_RETRANS)tp->retrans_out -= acked_pcount;flag |= FLAG_RETRANS_DATA_ACKED;...if (sacked & TCPCB_LOST)tp->lost_out -= acked_pcount;

内核版本 5.0

Reno与RACK对丢失/重传报文的标记相关推荐

  1. QoS服务质量三DiffServ模型报文的标记及PHB

    QoS服务质量三DiffServ模型报文的标记及PHB 2.3.5.报文的标记方法 2.3.5.1.IP Prececence 2.3.5.2.DSCP 2.3.5.3.IPv6报文 2.3.5.4. ...

  2. TCP系列23—重传—13、RACK重传

    一.RACK概述 RACK(Recent ACKnowledgment)是一种新的基于时间的丢包探测算法,RACK的目的是取代传统的基于dupthresh门限的各种快速重传及其变种.前面介绍的各种基于 ...

  3. java 美团 订单推送,记一次美团外卖推送报文丢失

    记一次美团外卖推送报文丢失1.环境介绍2.问题追踪step1 查推送日志step2 查日志文件step3 追踪代码step4 追踪代码调用链3.问题重现step1 在spring cloud 启动的时 ...

  4. 关于TCP报文段丢失,确认号的选择

    主机A向主机B连续发送了两个TCP报文段,其序号分别为70和100. 解析:即题目的意思就是0-69已经全部接收完成,现在就是A发送第一个是70-99和第二个是100-n的报文段 (1)第一个报文段携 ...

  5. 记一次美团外卖推送报文丢失

    记一次美团外卖推送报文丢失 1.环境介绍 2.问题追踪 step1 查推送日志 step2 查日志文件 step3 追踪代码 step4 追踪代码调用链 3.问题重现 step1 在spring cl ...

  6. TCP的拥塞控制--慢启动,拥塞避免,快重传,快速恢复

    拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致引起这部分乃至整个网络性能下降的现象,严重时甚至会导致网络通信业务陷入停顿,即出现死锁现象.这种现象跟公路网中经常所见的 ...

  7. TCP的拥塞避免、超时重传、快速重传、快速恢复

    转自:http://blog.csdn.net/itmacar/article/details/12278769 感谢博主的辛勤成果! 为了防止网络的拥塞现象,TCP提出了一系列的拥塞控制机制.最初由 ...

  8. 计网实验四—TCP Tahoe与Reno运行机制对比分析

    计算机网络实验四--TCP Tahoe与Reno运行机制对比分析 一.实验目的 二.实验内容 三.实验原理 TCP 基于窗口的拥塞控制策略 1.加法增加乘法减少(AIMD)窗口算法 2. TCP 拥塞 ...

  9. TCP的拥塞控制 (Tahoe Reno NewReno SACK)

    引言 计算机网络中的带宽.交换结点中的缓存和处理机等,都是网络的资源.在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏.这种情况就叫做拥塞. 拥塞控制就是防止过多 ...

  10. 你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了...

    每日一句英语学习,每天进步一点点: 来自:小林coding 前言 前一篇「硬不硬你说了算!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题」得到了很多读者的认可,在此特别感谢你们的认可, ...

最新文章

  1. 赛迪研究院发布《2019量子计算发展白皮书》
  2. 抽象工厂和工厂设计模式之间有什么区别?
  3. c++ 11新特性总结_JDK1.8新特性Stream和Collectors19个常用示例总结
  4. 选定用户与用户组启动流程(学习笔记)
  5. 戴尔服务器显示e1810,戴尔服务器提示: PowerEdge2950 E1810 HDD 1 Fault该如何解决?求帮助!!!...
  6. Quickr for Portal相关网址
  7. ProtocolBuffer for Objective-C 运行环境配置(真正测试过的)
  8. Vue-cli 2在webpack内使用雪碧图(响应式)
  9. Spring Cloud服务提供者与服务消费者怎么运作的?
  10. 4.dialog 工具
  11. 常见的 web server
  12. 计算机通信的应用,计算机技术在通信中的应用
  13. go语言快速入门:流程控制(7)
  14. MySQL索引的底层数据结构衍变史
  15. 什么是期货、现货?//2021-2-1
  16. Vue项目中常见问题(55)提交订单、获取订单号、展示支付信息
  17. win8系统计算机属性在哪个文件夹,Win8如何更改文件夹的只读或系统属性
  18. 华硕x550vc——6年后的性能测试
  19. 华钜同创:各卖家注意!亚马逊发布新规,强制卖家上传GTIN
  20. 【python爬虫专项(28)】链家二手房源数据采集1(分页信息采集)

热门文章

  1. c语言表达式必须包含指针类型,c – 错误:表达式必须是指向完整对象类型的指针(?)...
  2. delphi技巧总结收集
  3. svn之黄色感叹号处理方法
  4. windows10系统插耳机有回声解决办法?
  5. 29岁程序员,该怎么在写作、沟通、能力方面提升自己?
  6. android: 禁止多点触控
  7. 实战分享:大学生兼职赚钱创业,财务自由,顺势布局
  8. 组装http报文调用小黄鸡网页端消息接口
  9. 信息奥赛课课通(C++)p139-例3幸运数的划分
  10. 通过计算机主机数来划分子网,计算机网络知识梳理(2)——子网掩码及网络划分...