Reno与RACK对丢失/重传报文的标记

2023-12-19 09:48

本文主要是介绍Reno与RACK对丢失/重传报文的标记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

主要涉及到两个变量,一是重传报文计数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对丢失/重传报文的标记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511748

相关文章

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(Buffer Pool)中进行。例如,执行一条 UPDATE 语句修改了某一行数据,对应的缓

三色标记(Tri-color marking)

维基百科部分 原文 https://en.wikipedia.org/wiki/Tracing_garbage_collection#TRI-COLOR Because of these performance problems, most modern tracing garbage collectors implement some variant of the tri-color ma

C/C++ 网络聊天室在线聊天系统(整理重传)

知识点: TCP网络通信 服务端的流程: 1.创建socket套接字 2.给这个socket绑定一个端口号 3.给这个socket开启监听属性 4.等待客户端连接 5.开始通讯 6.关闭连接 解释: socket:类似于接口的东西,只有通过这个才能跟对应的电脑通信。 每一台电脑都有一个IP地址,一台电脑上有多个应用,每个应用都会有一个端口号。 socket一般分为两种类型,一种是通讯,一种是监听

【造轮子】纯C++实现的联通组件标记算法

学习《OpenCV应用开发:入门、进阶与工程化实践》一书 做真正的OpenCV开发者,从入门到入职,一步到位! 连接组件标记算法 连接组件标记算法(connected component labeling algorithm-CCL)是图像分析中最常用的算法之一,算法的实质是扫描一幅图像的每个像素,对于像素值相同的分为相同的组(group),最终得到图像中所有的像素连通组件。扫描的方式可以是从

六种msvcp110.dll丢失修复的方法分享,有效快速修复msvcp110.dll丢失

在日常使用电脑的过程中,我们可能会遭遇各种程序运行错误,其中“msvcp110.dll丢失”是一种非常常见的问题。这个问题通常发生在尝试启动某些程序时,系统会弹出一个错误消息,提示“程序无法启动,因为计算机缺少msvcp110.dll”,这可能会让用户感到困惑和无助。幸运的是,这个问题有多种解决方法,本文将指导你通过几种简单的步骤来修复“msvcp110.dll丢失”的问题,让你的程序回到正常运行

LabVIEW开发FPGA方法与FIFO数据丢失处理

开发基于NI 7975R FPGA的系统涉及一系列流程,包括驱动安装、LabVIEW项目设置、开发调试、编译和与Windows系统的通信。重点在于FIFO的正确配置,避免数据丢失是关键环节之一,尤其是在使用高速数据流传输时。以下将详细介绍这些过程,并重点讨论FIFO数据丢失的原因与解决方案。 FPGA开发流程 驱动安装与工具准备:开发FPGA需要安装LabVIEW FPGA模块以及N

[数据集][目标检测]井盖丢失未盖破损检测数据集VOC+YOLO格式2890张5类别

数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2890 标注数量(xml文件个数):2890 标注数量(txt文件个数):2890 标注类别数:5 标注类别名称:["broke","circle","good","lose","uncovered"] 每个类别标

兔子--Android Support v4包丢失的解决办法

在开发中,Android Support v4包丢失的解决办法: Project->properties->Java Build Path->Libraries->Add External Jars 中加入sdk目录下的extras/android/support/v4/android-support-v4.jar (如果找不到,则需要用sdk manager下载andro

python画图|垂线标记系列

进行了一段时间的直方图学习之后,发现python的matplo居然还支持画垂线标记图,赶紧把它记录下来。 直方图绘制教程见下述链接: 【a】直方图绘制基础教程:python画图|直方图绘制教程-CSDN博客 【b】 直方图绘制进阶教程:python画图|直方图绘制教程进阶-CSDN博客 【c】 堆叠直方图绘制教程:python画图|堆叠直方图绘制-CSDN博客 【d】并列直方图绘制教程:

鸿蒙(API 12 Beta6版)超帧功能开发【顶点标记】

超帧提供两种运动估计模式供开发者选择:分别为基础模式和增强模式。其中增强模式需要对绘制顶点的Draw Call命令进行额外的标记,在相机和物体快速运动的游戏场景超帧效果较基础模式更优,能够有效改善拖影问题。本章主要介绍增强模式的运动估计原理及顶点标记方法。 说明 Draw Call:指图形驱动库(OpenGL ES)中进行绘制的命令,例如glDrawElements、glDrawArrays、