上篇文章中我们主要说明如何skip到一个SACK块对应的开始段,如何walk这个SACK块包含的段,而没有涉及到

如何标志一个段的记分牌。37版本把给一个段打标志的内容独立出来,这就是tcp_sacktag_one()。

本文主要内容:tcp_sacktag_one(),给一个段打上标志。

Author:zhangskd @ csdn

标志一个包

tcp_sacktag_walk()用于遍历块中的数据包,最终会调用tcp_sacktag_one()来标志一个数据包的记分牌,

即TCP_SKB_CB(skb)->sacked。

记分牌有哪些标志呢?

#define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block, 标志S */

#define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted,标志R */

#define TCPCB_LOST 0x04 /* SKB is lot,标志L */

#define TCPCB_TAGBITS 0x07 /* All tag bits,标志位掩码 */

#define TCPCB_EVER_RETRANS 0x08 /* Ever retransmitted frame,曾经重传过 */

#define TCPCB_RETRANS (TCPCB_SACKED_RETRANS | TCPCB_EVER_RETRANS)

以上标志的说明如下:

We have three tag bits: SACKED(S)、RETRANS(R) and LOST(L).

Packets in queue with these bits set are counted in variables sacked_out、retrans_out and lost_out.

tag标志可能的6种情况:

Tag        InFlight        Description

0             1                   orig segment is in flight,正常情况

S             0                   nothing flies, orig reached receiver.

L              0                  nothing flies, orig lost by net.

R             2                  both orig and retransmit is in flight.

L|R          1                  orig is lost, retransmit is in flight.

S|R          1                  orig reached receiver, retrans is still in flight.

(L|S|R is logically valid, it could occur when L|R is sacked, but it is equivalent to plain S and code

short-curcuits it to S.

L|S is logically invalid, it would mean -1 packet in flight.

以上6种情况是由以下事件触发的:

These 6 states form finite state machine, controlled by the following events:

1. New ACK (+SACK) arrives. (tcp_sacktag_write_queue())

2. Retransmission. (tcp_retransmit_skb(), tcp_xmit_retransmit_queue())

3. Loss detection event of one of three flavors:

A. Scoreboard estimator decided the packet is lost.

A'. Reno "three dupacks" marks head of queue lost.

A''. Its FACK modification, head until snd.fack is lost.

B. SACK arrives sacking data retransmitted after never retransmitted hole was sent out.

C. SACK arrives sacking SND.NXT at the moment, when the segment was retransmitted.

4. D-SACK added new rule: D-SACK changes any tag to S.

static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
struct tcp_sacktag_state *state, int dup_sack, int pcount)
{
struct tcp_sock *tp = tcp_sk(sk);
u8 sacked = TCP_SKB_CB(skb)->sacked;
int fack_count = state->fack_count; /* Account D-SACK for retransmitted packet.
* 如果此skb属于DSACK块,且skb被重传过。即此前tag为R、或者R|S。
*/
if (dup_sack && (sacked & TCPCB_RETRANS)) { /* 位于上次进入Recovery或Loss之后 */
if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
tp->undo_retrans--; /* 如果减为0,那么说明之前重传都是不必要的,进行拥塞控制调整撤销 */ if (sacked & TCPCB_SACKED_ACKED) /* 如果这个包已经被SACK过,那么说明是乱序 */
state->reord = min(fack_count, state->reord); /* 更新乱序队列的起始点 */
} /* Nothing to do; acked frame is about to be dropped (was ACKed).
* 这个skb已经被正常确认了,不用再处理了,它即将被丢弃。
*/
if (! after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
return sacked; /* 如果skb还没有被SACK,那么进行处理 */
if (! (sacked & TCPCB_SACKED_ACKED)) { /* 有R标志,表示被重传过 */
if (sacked & TCPCB_SACKED_RETRANS) {
/* If the segment is not tagged as lost, we do not clear RETRANS, believing
* that retransmission is still in flight.
* 如果之前的标志是:R | L,那么好,现在收到包了,可以清除R和L。
* 如果之前的标志是:R,那么认为现在收到的是orig,重传包还在路上,所以不用干活:)
*/
if (sacked & TCPCB_LOST) {
sacked &= ~(TCPCB_LOST | TCPCB_SACKED_RETRANS); /* 取消L和R标志 */
tp->lost_out -= pcount; /* 更新LOST包个数 */
tp->retrans_out -= pcount; /* 更新RETRANS包个数 */
} } else { /* 没有R标志 */
if (! (sacked & TCPCB_RETRANS)) {
/* New sack for not retransmitted frame, which was in hole. It is reordering.
* 如果一个包落在highest_sack之前,它即没被SACK过,也不是重传的,那么
* 它肯定是乱序了,到现在才被SACK。
*/
if (before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp)))
state->reord = min(fack_count, state->reord); /* 记录乱序的起始位置 */ /* SACK enhanced F-RTO (RFC4138; Appendix B) */
if (! after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark))
state->flag |= FLAG_ONLY_ORIG_SACKED; /* SACKs only non-rexmit sent before RTO */
} /* 如果它有LOST标志,既然收到了,那么要撤销了 */
if (sacked & TCPCB_LOST) {
sacked &= ~TCPCB_LOST; /* 撤销LOST标志 */
tp->lost_out -= pcount; /* 更新LOST包个数 */
}
} sacked |= TCPCB_SACKED_ACKED; /* 给skb打上SACK标志,就是这里:) */
state->flag |= FLAG_DATA_SACKED;
tp->sacked_out += pcount; /* 更新SACK包个数 */
fack_count += pcount; /* fackets_out =sacked_out + lost_out,也跟着更新 */ /* 没有使用FACK时 */
if (! tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) &&
before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->lost_skb_hint)->seq))
tp->lost_cnt_hint += pcount; if (fack_count > tp->fackets_out)
tp->fackets_out = fack_count; /* 更新tp->fackets_out */
} /* D-SACK. We can detect redundant retransmission in S|R and plain R frames and clear it.
* undo_retrans is decreased above, L|R frames are accounted above as well.
* 如果skb被D-SACK,并且它的重传标志还未被清除,那么现在清除。
*/
if (dup_sack && (sacked & TCPCB_SACKED_RETRANS)) {
sacked &= ~TCPCB_SACKED_RETRANS; /* 清除重传标志 */
tp->retrans_out -= pcount; /* 更新重传包个数 */
} return sacked; /* 返回此skb的记分牌 */
}

TCP的核心系列 — SACK和DSACK的实现(六)的更多相关文章

  1. TCP的核心系列 — SACK和DSACK的实现(一)

    TCP的实现中,SACK和DSACK是比较重要的一部分. SACK和DSACK的处理部分由Ilpo Järvinen (ilpo.jarvinen@helsinki.fi) 维护. tcp_ack() ...

  2. TCP的核心系列 — SACK和DSACK的实现(二)

    和18版本相比,37版本的SACK和DSACK的实现做了很多改进,最明显的就是需要遍历的次数少了, 减少了CPU的消耗.37版的性能提升了,代码有大幅度的改动,逻辑也更加复杂了. 本文主要内容:37版 ...

  3. TCP的核心系列 — SACK和DSACK的实现(七)

    我们发送重传包时,重传包也可能丢失,如果没有检查重传包是否丢失的机制,那么只能依靠超时来恢复了. 37版本把检查重传包是否丢失的部分独立出来,这就是tcp_mark_lost_retrans(). 在 ...

  4. TCP的核心系列 — SACK和DSACK的实现(三)

    不论是18版,还是37版,一开始都会从TCP的控制块中取出SACK选项的起始地址. SACK选项的起始地址是保存在tcp_skb_cb结构的sacked项中的,那么这是在什么时候做的呢? SACK块并 ...

  5. TCP的核心系列 — SACK和DSACK的实现(五)

    18版本对于每个SACK块,都是从重传队列头开始遍历.37版本则可以选择性的遍历重传队列的某一部分,忽略 SACK块间的间隙.或者已经cache过的部分.这主要是通过tcp_sacktag_skip( ...

  6. TCP的核心系列 — SACK和DSACK的实现(四)

    和18版本不同,37版本把DSACK的检测部分独立出来,可读性更好. 37版本在DSACK的处理中也做了一些优化,对DSACK的两种情况分别进行处理. 本文主要内容:DSACK的检测.DSACK的处理 ...

  7. TCP的核心系列 — ACK的处理(二)

    本文主要内容:tcp_ack()中的一些细节,如发送窗口的更新.持续定时器等. 内核版本:3.2.12 Author:zhangskd @ csdn 发送窗口的更新 什么时候需要更新发送窗口呢? (1 ...

  8. TCP的核心系列 — ACK的处理(一)

    TCP发送数据包后,会收到对端的ACK.通过处理ACK,TCP可以进行拥塞控制和流控制,所以 ACK的处理是TCP的一个重要内容.tcp_ack()用于处理接收到的ACK. 本文主要内容:TCP接收A ...

  9. TCP的核心系列 — 重传队列的更新和时延的采样(二)

    在tcp_clean_rtx_queue()中,并非对每个ACK都进行时延采样.是否进行时延采样,跟这个ACK是否为 重复的ACK.这个ACK是否确认了重传包,以及是否使用时间戳选项都有关系. 本文主 ...

随机推荐

  1. Unity插件 - MeshEditor(八)模型镜像特效

    将静态模型(带MeshFilter)按指定轴向.指定距离克隆一个镜像物体出来,思路很简单,将模型的顶点坐标按指定轴取反,并累加上设定的距离值,然后就完毕了!不过,因为镜像体的顶点镜像于之前模型的顶点, ...

  2. Linux 高性能服务器编程——多线程编程

    问题聚焦:     在简单地介绍线程的基本知识之后,主要讨论三个方面的内容:    1 创建线程和结束线程:    2 读取和设置线程属性:    3 线程同步方式:POSIX信号量,互斥锁和条件变量 ...

  3. SpriteKit给游戏弹跳角色添加一个高度标示器

    这是一个类似于跳跃涂鸦的小游戏,主角不断吃能量球得到跳跃能量向更高的地方跳跃,如果图中碰到黑洞就挂了- 在游戏调试过程中如果能实时知道主角的高度就好了,这将有助于程序猿动态的判断游戏胜败逻辑. 你可以 ...

  4. UE4 C++与蓝图交互

    一.C++调用蓝图的函数 本来应该有一个很好的示例,但一下却忘了适用于哪些地方,只有简单写一个步骤了. 1.新建一个C++类继承Actor,名称随意,我这里继承了一个SplineMesh,一样de,并 ...

  5. 高通msm8994性能及温度监测脚本

    [plain] view plain copystartTime=$(date +%Y-%m-%d-%H-%M-%S)  pathName="/data/cpu_logs"  fi ...

  6. 如何使用excel画甘特图

    甘特图小伙伴们都非常的熟悉,首先小编简单的向各位小伙伴介绍一下什么是甘特图,甘特图内在思想简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间.基本是一条线条图,横轴 ...

  7. 1.QT中的容器QVector,QList,QSet,QMap,QQueue,QStack,QMultiMap,QSingleList等

    1  新建一个项目 在pro文件中只需要加上CONFIG += C++11 main.cpp #include <QMap> int main() { QMap<int,QStrin ...

  8. 怎样在Ubuntu 14.04中搭建gitolite git服务器

     1.   首先这里我们安装openssh-serveropenssh-client,如果你用的是VPS之类的一般都默认安装好了,不过运行一个这个命令不会有错的,如果有安装就会提示已安装. sud ...

  9. StringBuffer与StringBuilder详解

    刚刚在参加网易实习生在线考试的时候,出了一道选择题谈到了StringBuilder这个类的一些选项,虽然那道题自己做对了,但是也提醒了我应该好好了解一些StringBuffer与StringBuild ...

  10. Android进阶(二十八)上下文菜单ContextMenu使用案例

    上下文菜单ContextMenu使用案例 前言 回顾之前的应用程序,发现之前创建的选项菜单无法显示了.按照正常逻辑来说,左图中在"商品信息"一栏中应该存在选项菜单,用户可进行分享等 ...