TCP RTT 测不准饱受诟病:

  • 接收端可能开启 Delayed ACK ,Delay 延时不确定。
  • 接收端可能开启 LRO/GRO ,Merge 延时不确定。
  • 重传时无法区分原始数据包和重传数据包。

第三点还成了 QUIC 的反面教材。

果真如此?别人怎么教你,你就怎么记笔记,但凡跟笔记对不上的就是错的?

今晚,我来演示一种精确测量 RTT 的方法,你的笔记上肯定没有,但可以加上去。

这种方法的有趣之处恰哈因为它是在 Recovery 状态下测量。按照 TCP 规范,接收端在收到非连续报文时必须立刻 ACK,这避开了 Delayed ACK 的不确定性。

做法很简单:

  • 开启 timestamps 选项,该 opt 里的 tsval 可以 echo 回来,用该字段作为识别标识。
  • 为重传 skb 打上 anch = opts->tsval + 1 作为 tsval,发送之,记录当前 ts_us 到 skb。
  • 为其它传输 skb 及 重传 skb 避开 anch 作为 tsval,取 anch + 1 作为其 tsval。
  • 观测 ACK 的 tsecr,扫描 rtx queue,若 ACK.tsecr == anch,now_us - skb.ts_us 则为精确 RTT。

下面是一个简单的 POC 脚本:

#!/usr/local/bin/stap -g
%{#include <linux/tcp.h>
#include <net/tcp.h>__u32 anch = 0;
__u32 skip = 0;%}function set_ts(tpp:long, opt:long)
%{struct tcp_sock *tp = (struct tcp_sock *)STAP_ARG_tpp;struct sock *sk = (struct sock *)tp;struct inet_connection_sock *icsk = inet_csk(sk);struct tcp_out_options *opts = (struct tcp_out_options *)STAP_ARG_opt;if (tp != NULL &&ntohs(inet_sk(sk)->inet_dport) == 5001 &&icsk->icsk_ca_state == TCP_CA_Recovery) {if (opts->tsval == skip) { // 避开 anchopts->tsval ++; // 不要避开太多,当心对端 PAWS 检测} else if (skip == 0){ // 设置 anch 作为识别符anch = opts->tsval; opts->tsval = anch;skip = anch;STAP_PRINTF("set ts: %d\n", anch);}}if (tp != NULL && icsk->icsk_ca_state == TCP_CA_Open) {skip = 0;anch = 0;}
%}function get_ts(skk:long)
%{struct sock *sk = (struct sock *)STAP_ARG_skk;struct tcp_sock *tp = (struct tcp_sock *)sk;struct inet_connection_sock *icsk = inet_csk(sk);if (ntohs(inet_sk(sk)->inet_dport) == 5001 &&icsk->icsk_ca_state == TCP_CA_Recovery) {__u32 ecr = tp->rx_opt.rcv_tsecr + tp->tsoffset;if (skip == ecr) { // 找到确认打上 anch 的重传包的 ACK。u32 delta = tcp_time_stamp(tp) - ecr + tp->tsoffset;delta = delta * (USEC_PER_SEC / TCP_TS_HZ);STAP_PRINTF("echo ts: %d  anch: %d  rtt_us: %d srtt_us: %d\n", ecr, anch, delta, tp->srtt_us>>3);skip = 0;anch = 0;}}
%}probe kernel.function("tcp_options_write")
{set_ts($tp, $opts);
}probe kernel.function("tcp_ack_update_rtt")
{get_ts($sk);
}

有趣的是,timestamps 在测量 RTT 过程中没有参与任何与时间相关的运算,仅作为识别符。实际中, TCP timestamps 精度太低,不能识别 us,我曾一直以为 TCP 完全依赖它计算 RTT,但并没有:

// 实在是不堪大用
static inline u32 tcp_skb_timestamp(const struct sk_buff *skb)
{return div_u64(skb->skb_mstamp_ns, NSEC_PER_SEC / TCP_TS_HZ);
}

上述脚本并未涉及扫描 rtx queue 的逻辑,因为需要修改 Linux TCP 源码,这不是晚上一两个小时能搞定的。

TCP 传输优化中,可以这么利用这个精确的 RTT:

  • 若精确的 RTT 与 srtt_us 相同未显著增大,大概率非拥塞丢包,可适当激进,重传完成后可 undo。
  • 在整个 Recovery 状态,均可使用这种方法进行精确 RTT 测量,并跟踪其与 srtt_us 的差值。
  • 配合前面的半程 RTT 抖动检测,即便是 Data 半程的抖动,也能区分是抖动还是拥塞。

玩法还是挺多的…

但如果不支持 timestamps 怎么办?

目标不是用 timestamps,目标是需要一个字段能 echo 回来用来将 Data 和 ACK 对应起来就行。

显然,seq 也可 echo 回来,把它 echo 回来的就是 ACK。为捕捉标识以精确计算 RTT 从而判断是否拥塞,最终决策是否 undo,需花式重传:

  • 若 una~una + mss 作为一个 skb 传输并被 mark lost,则重传 una~una + fk(fk 取 123 或 222等花值均可)。
  • 记录当前 ts_us 到该重传 skb。
  • 保留 una + fk ~ una + mss 为空洞,以期接收端及时回复 ACK。
  • 观测 ACK,扫描 rtx queue,若 ACK == una + fk == skb.end_seq,now_us - skb.ts_us 则为精确 RTT。

花式重传可以区分原始包和重传包:

  • 若 ACK 覆盖 una + fk,则该 ACK 非重传包触发,大概率非拥塞,无效重传,但情况复杂,忽略。
  • 若 ACK 等于 una + fk,则该 ACK 为重传包触发,按本文上述方法计算 RTT,与 srtt_us 比较。

后面的玩法就和 timestamps 开启时一样的。

花式传输还可以更花,后面单独介绍,本文仅和 RTT 测量相关。

至此,我们已经有了三个信息:

  • Open 状态下常规 srtt_us。
  • 任意状态两个半程 ts 的抖动。
  • Recovery 状态精确的 RTT。

其中后两个都是通过额外的想法挖掘的。我还是老观念,充分利用信息,把现有信息运用到极致后再抱怨信息不够。

这个思路很常用,给定一个数学函数,你能看到它的图像,但这就够了吗?对它求导,对它的导数再求导,再再求导…你就可以看到它的单调性,凸凹,极值等别的性质了。

天气闷热,高温黄色预警,总也不下雨,白天用派森操作意克塞尔表格折腾了一天,晚上换点事情做。随笔记录。

浙江温州皮鞋湿,下雨进水不会胖。

TCP RTT测量妙计相关推荐

  1. TCP RTT与TCP RTO关系详解

    本文目录 1,TCP的RTT和TCP的RTO的定义 1.1,什么是TCP的RTT 1.2,什么是TCP的RTO 2,TCP的当前RTT和RTO的计算 2.1,开始讲RTT计算算法前,我们先理解一下TC ...

  2. TCP RTT 采集方法

    TCP RTT 采集方法值得一提: 正常状态采集的 RTT 因加入了接收端 Delayed ACK,积累 ACK 等原因而偏大. Disorder,Recovery 状态采集的 RTT 相对准确,通过 ...

  3. Linux内核tcp时间测量,linux内核 – 测试linux内核中函数的执行时间

    我使用Linux安全模块挂钩来添加一些自定义功能到recv()系统调用.与原始的recv()相比,我想测量这个功能的开销.我写了一个简单的tcp服务器,我运行与没有我的模块.这个tcp服务器调用rec ...

  4. TCP中RTT时延的理解

    最近服务器环境部署了tcprtt网络时延监控,发现不同服务器不同节点之间的RTT时延表象非常奇怪,无法准确的判断服务器的网络情况.因此需要弄清楚什么是RTT,以及能否作为服务器网络性能的检测指标. 1 ...

  5. 排队理论解释TCP/IP网络拥塞是如何影响TCP的RTT的波动

    部门团建,大家都去长隆了,也有去澳门广西的...我去了梦里...本来我也报了名的,想单独带着女儿独处两天,不光为了培养跟女儿的感情,也是想让老婆歇两天...只可惜女儿最近生病,去不了了,六一儿童节的表 ...

  6. 计算机网络|iperf测量不同拥塞控制下TCP传输性能

    系列文章目录 待更新- 文章目录 系列文章目录 前言 一.实验准备 二.操作内容及步骤 1.内核相关指令 2.iperf or iperf3 什么是iperf/iperf3? iperf特性 3.tc ...

  7. TCP之超时重传机制

    TCP协议是一种面向连接的可靠的传输层协议,它保证了数据的可靠传输,对于一些出错.超时丢包等问题TCP设计了超时重传机制,其基本原理:在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送 ...

  8. QUIC 是如何解决TCP 性能瓶颈的?

    作者:流云IoT 链接:https://blog.csdn.net/m0_37621078/article/details/106506532 重新整理:极客重生 文章目录 一.QUIC 如何解决TC ...

  9. ​TCP 拥塞控制详解

    作者:engleliu,腾讯 PCG 开发工程师 本文主要介绍 TCP 拥塞控制算法,内容多来自网上各个大佬的博客及<TCP/IP 详解>一书,在此基础上进行梳理总结,与大家分享.因水平有 ...

  10. 理解 TCP(五):可靠性交付的实现

    更好阅读体验:<理解 TCP 和 UDP>- By Gitbook TCP 是一种提供可靠性交付的协议. 也就是说,通过 TCP 连接传输的数据,无差错.不丢失.不重复.并且按序到达. 但 ...

最新文章

  1. SQL Server 存储过程的分页方案比拼
  2. TYVJ1415 差分约束
  3. js 判断一个元素是否存在
  4. (一)TestNG测试框架之HelloWorld入门
  5. python快速排序解析_快速排序python实现总结
  6. git revert 后再次merge_git如何回滚错误合并的分支
  7. math python 向上取整_Python成为专业人士笔记-各数学运算操作深度剖析
  8. 马斯克:我上大学时就想创立电动汽车公司
  9. 第二周四则运算汇报及总结
  10. python嵌套字典的建立_python学习之第八篇——字典嵌套之字典中嵌套字典
  11. 优秀的项目经理都会用这60个项目管理工具模板,可直接编辑套用
  12. 图解冰河木马一次使用过程
  13. SLIC超像素分割并保存分割得到的超像素块,python代码
  14. 【钉钉-场景化能力包】阿里商旅助力费控报销
  15. 机器学习两种参数估计方法:最大似然估计和最小二乘法估计
  16. 小达同学软件测试第三讲
  17. 去除下拉框上向下的箭头
  18. 活期账户10亿个+日均交易4亿笔,建设银行如何啃下系统转型的“硬骨头”?
  19. Failed to evaluate mask initialization commands
  20. 基于ffmpeg+SDL 实时播放摄像头视频

热门文章

  1. 小米怎么快速回到顶部_实在没想到,小米有6种截屏方法!以前只知道3种,实在太吃亏了...
  2. 2022强网杯web(部分)
  3. imitate wechat - 0
  4. Java 多线程 生产者和消费者
  5. 商务统计_5 用图表演示数据 - 茎叶图
  6. 大数据应用场景有哪些?一篇文章告诉你
  7. LVS高性能原因揭秘
  8. ZYNQ PL 添加IP 串口UART AXI UART16550
  9. 加速 Android 开发的五大开源网站
  10. html5 blockquote,HTML5 Blockquote引用区块使用实例