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

相关文章

mss32.dll文件丢失怎么办? 电脑提示mss32.dll丢失的多种修复方法

《mss32.dll文件丢失怎么办?电脑提示mss32.dll丢失的多种修复方法》最近,很多电脑用户可能遇到了mss32.dll文件丢失的问题,导致一些应用程序无法正常启动,那么,如何修复这个问题呢... 在电脑常年累月的使用过程中,偶尔会遇到一些问题令人头疼。像是某个程序尝试运行时,系统突然弹出一个错误提

电脑提示找不到openal32.dll文件怎么办? openal32.dll丢失完美修复方法

《电脑提示找不到openal32.dll文件怎么办?openal32.dll丢失完美修复方法》openal32.dll是一种重要的系统文件,当它丢失时,会给我们的电脑带来很大的困扰,很多人都曾经遇到... 在使用电脑过程中,我们常常会遇到一些.dll文件丢失的问题,而openal32.dll的丢失是其中比较

电脑win32spl.dll文件丢失咋办? win32spl.dll丢失无法连接打印机修复技巧

《电脑win32spl.dll文件丢失咋办?win32spl.dll丢失无法连接打印机修复技巧》电脑突然提示win32spl.dll文件丢失,打印机死活连不上,今天就来给大家详细讲解一下这个问题的解... 不知道大家在使用电脑的时候是否遇到过关于win32spl.dll文件丢失的问题,win32spl.dl

电脑提示msvcp90.dll缺少怎么办? MSVCP90.dll文件丢失的修复方法

《电脑提示msvcp90.dll缺少怎么办?MSVCP90.dll文件丢失的修复方法》今天我想和大家分享的主题是关于在使用软件时遇到的一个问题——msvcp90.dll丢失,相信很多老师在使用电脑时... 在计算机使用过程中,可能会遇到 MSVCP90.dll 丢失的问题。MSVCP90.dll 是 Mic

电脑开机提示krpt.dll丢失怎么解决? krpt.dll文件缺失的多种解决办法

《电脑开机提示krpt.dll丢失怎么解决?krpt.dll文件缺失的多种解决办法》krpt.dll是Windows操作系统中的一个动态链接库文件,它对于系统的正常运行起着重要的作用,本文将详细介绍... 在使用 Windows 操作系统的过程中,用户有时会遇到各种错误提示,其中“找不到 krpt.dll”

电脑报错cxcore100.dll丢失怎么办? 多种免费修复缺失的cxcore100.dll文件的技巧

《电脑报错cxcore100.dll丢失怎么办?多种免费修复缺失的cxcore100.dll文件的技巧》你是否也遇到过“由于找不到cxcore100.dll,无法继续执行代码,重新安装程序可能会解... 当电脑报错“cxcore100.dll未找到”时,这通常意味着系统无法找到或加载这编程个必要的动态链接库

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(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),最终得到图像中所有的像素连通组件。扫描的方式可以是从