/*
* TCP Westwood+: end-to-end bandwidth estimation for TCP
*
* Angelo Dell'Aera: author of the first version of TCP Westwood+ in Linux 2.4
*
* Support at http://c3lab.poliba.it/index.php/Westwood
* Main references in literature:
*
* - Mascolo S, Casetti, M. Gerla et al.
* "TCP Westwood: bandwidth estimation for TCP" Proc. ACM Mobicom 2001
*
* - A. Grieco, s. Mascolo
* "Performance evaluation of New Reno, Vegas, Westwood+ TCP" ACM Computer
* Comm. Review, 2004
*
* - A. Dell'Aera, L. Grieco, S. Mascolo.
* "Linux 2.4 Implementation of Westwood+ TCP with Rate-Halving :
* A Performance Evaluation Over the Internet" (ICC 2004), Paris, June 2004
*
* Westwood+ employs end-to-end bandwidth measurement to set cwnd and
* ssthresh after packet loss. The probing phase is as the original Reno.
*/ #include <linux/mm.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/inet_diag.h>
#include <net/tcp.h> /* TCP Westwood structure */
struct westwood {
u32 bw_ns_est; /*中间变量,经过一次平滑后的带宽值 first bandwidth estimation..not too smoothed 8) */
u32 bw_est; /*最终估计的带宽值 bandwidth estimate */
u32 rtt_win_sx; /*采样周期的起始点,一个RTT后结束 here starts a new evaluation... */
u32 bk; //在某个时间段delta内确认的字节数
u32 snd_una; /*snd_una历史记录,用于计算bk used for evaluating the number of acked bytes */
u32 cumul_ack; //在慢速路径下,一个ACK确认的数据量 cumulative ack
u32 accounted; //在慢速路径下,收到的重复数据包个数
u32 rtt; //当前RTT值,以毫秒为单位,每收到一个ACK都更新
u32 rtt_min; /*最小RTT值,以毫秒为单位,inimum observed RTT */
u8 first_ack; /*是否第一个ack包 flag which infers that this is the first ack */
u8 reset_rtt_min; /*是否重置采样周期 Reset RTT min to next RTT sample*/
}; /* TCP Westwood functions and constants */
#define TCP_WESTWOOD_RTT_MIN (HZ/20) /* 50ms */
#define TCP_WESTWOOD_INIT_RTT (20*HZ) /* 20000ms 太保守??? maybe too conservative?! */ /*
westwood在丢包率较高的无线网络中表现较好。
Reno对随机丢包和拥塞丢包都较为敏感,随机丢包会导致Reno不必要的降低拥塞窗口和慢启动阈值。
在westwood算法中,需要强调的一点是:丢包对带宽的影响不大。
每个RTT采样一次带宽值,而这次样本只占bw_est的1/64。丢包后进入快速恢复阶段,尽管在快速恢复阶段
中得到的几个采样值较小,但是整体的bw_est却没有太大的减小。
来看一下为什么westwood对随机丢包不敏感。
(1)随机丢包
丢包前:cwnd = bw_est * RTT
丢包后:cwnd = bw_est * RTTmin
因为是随机丢包,所以丢包前的RTT只是比RTTmin略大。丢包后的bw_est也只是微略减小。
所以丢包后的cwnd只是微略的减小。
(2)拥塞丢包
丢包前:cwnd = bw_est * RTTmax => BDP + Queue
丢包后:cwnd = bw_est * RTTmin => BDP
因为是拥塞丢包,所以丢包前的bw_est已经是连接的最大带宽,并且时延也达到了最大值。
这是丢包后就达到了完全利用BDP,同时使Queue为空的效果。
可以看到,westwood对随机丢包和拥塞丢包采取同样的算法来处理,却能达到不同的效果。
但是,westwood不能主动的区分随机丢包和拥塞丢包。
*/ /*
* @tcp_westwood_create
* This function initializes fields used in TCP Westwood+,
* it is called after the initial SYN, so the sequence numbers
* are correct but new passive connections we have no
* information about RTTmin at this time so we simply set it to
* TCP_WESTWOOD_INIT_RTT. This value was chosen to be too conservative
* since in this way we're sure it will be updated in a consistent
* way as soon as possible. It will reasonably happen within the first
* RTT period of the connection lifetime.
*/
static void tcp_westwood_init(struct sock *sk)
{ //初始化westwood拥塞算法的参数
struct westwood *w = inet_csk_ca(sk); w->bk = ;
w->bw_ns_est = ;
w->bw_est = ;
w->accounted = ;
w->cumul_ack = ;
w->reset_rtt_min = ;
w->rtt_min = w->rtt = TCP_WESTWOOD_INIT_RTT;
w->rtt_win_sx = tcp_time_stamp;//jiffies毫秒
w->snd_una = tcp_sk(sk)->snd_una;
w->first_ack = ;
} /*
* @westwood_do_filter
* Low-pass filter. Implemented using constant coefficients.
*/
static inline u32 westwood_do_filter(u32 a, u32 b)
{
return ((( * a) + b) >> ); //返回7a/8与1b/8之和
} static void westwood_filter(struct westwood *w, u32 delta)
{ //带宽过滤器
/* If the filter is empty fill it with the first sample of bandwidth */
if (w->bw_ns_est == && w->bw_est == ) {
//如果是第一次得到带宽测量样本
w->bw_ns_est = w->bk / delta;
w->bw_est = w->bw_ns_est;
} else {//如果已经有收到过测量样本了
w->bw_ns_est = westwood_do_filter(w->bw_ns_est, w->bk / delta);
w->bw_est = westwood_do_filter(w->bw_est, w->bw_ns_est);
}
} /*
* @westwood_pkts_acked
* Called after processing group of packets.
* but all westwood needs is the last sample of srtt.
*/
static void tcp_westwood_pkts_acked(struct sock *sk, u32 cnt, s32 rtt)
{ //每收到一个ACK时,会更新当前的RTT(w->rtt)
struct westwood *w = inet_csk_ca(sk); if (rtt > ) //这个参数rtt是以微秒为单位的,rtt为-1则不会执行转换
w->rtt = usecs_to_jiffies(rtt); //w->rtt是以毫秒为单位的
} /*
* @westwood_update_window
* It updates RTT evaluation window if it is the right moment to do
* it. If so it calls filter for evaluating bandwidth.
*/
static void westwood_update_window(struct sock *sk)
{ //每经过一个RTT后,采集一个新的测量样本,更新带宽估计值。
struct westwood *w = inet_csk_ca(sk);
s32 delta = tcp_time_stamp - w->rtt_win_sx; //计算时间差 /* Initialize w->snd_una with the first acked sequence number in order
* to fix mismatch between tp->snd_una and w->snd_una for the first
* bandwidth sample
*/
if (w->first_ack) {//如果是第一个ack包
w->snd_una = tcp_sk(sk)->snd_una;
w->first_ack = ;
} /*
* See if a RTT-window has passed.
* Be careful since if RTT is less than
* 50ms we don't filter but we continue 'building the sample'.
* This minimum limit was chosen since an estimation on small
* time intervals is better to avoid...
* Obviously on a LAN we reasonably will always have
* right_bound = left_bound + WESTWOOD_RTT_MIN
*/
//如果当前的rtt大于TCP_WESTWOOD_RTT_MIN,也就是超时了
if (w->rtt && delta > max_t(u32, w->rtt, TCP_WESTWOOD_RTT_MIN)) {
westwood_filter(w, delta);// 更新带宽估计值 w->bk = ;//清零确认字节数
w->rtt_win_sx = tcp_time_stamp;//重设取样周期开始时间
}
} static inline void update_rtt_min(struct westwood *w)
{//更新最小RTT
if (w->reset_rtt_min) { //如果非0
//当发生超时后,最小RTT可能不再准确,需要更新
w->rtt_min = w->rtt;
w->reset_rtt_min = ;
} else //如果为0
w->rtt_min = min(w->rtt, w->rtt_min);//更新最小RTT
} /*
* @westwood_fast_bw
* It is called when we are in fast path. In particular it is called when
* header prediction is successful. In such case in fact update is
* straight forward and doesn't need any particular care.
*/
//快速路径时的带宽估计值更新
//处于快速路径时调用,说明此时收到的数据包是顺序的,此时应该处于Open状态。
//这种状态下,收到新的ACK会使tp->snd_una前进。
//所以,tp->snd_una - w->snd_una能代表此ACK确认的数据量。
static inline void westwood_fast_bw(struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
struct westwood *w = inet_csk_ca(sk); westwood_update_window(sk); //更新带宽估计值 w->bk += tp->snd_una - w->snd_una; //累计确认的字节数
w->snd_una = tp->snd_una;//记录当前snd_una
update_rtt_min(w); //更新最小RTT
} /*
* @westwood_acked_count
* This function evaluates cumul_ack for evaluating bk in case of
* delayed or partial acks.
*/
//慢速路径时,计算所收到ACK确认的数据量。
//这时候的ACK可能是delayed ACK、partial ACK、duplicate ACK、
//cumulative ACK following a retransmission event. static inline u32 westwood_acked_count(struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
struct westwood *w = inet_csk_ca(sk); //计算此ACK确认的字节数
w->cumul_ack = tp->snd_una - w->snd_una; /* If cumul_ack is 0 this is a dupack since it's not moving
* tp->snd_una.
*/
//如果cumul_ack=0,那么此ACK是dupack,
//代表接收端收到一个数据包。
if (!w->cumul_ack) {
w->accounted += tp->mss_cache;//接收端保存的乱序数据包加一
w->cumul_ack = tp->mss_cache;//代表传输了一个数据包
} //如果cumul_ack > 1,则有可能是多种情况。
if (w->cumul_ack > tp->mss_cache) {
/* Partial or delayed ack 表示此ACK为partial ACK */
if (w->accounted >= w->cumul_ack) {
w->accounted -= w->cumul_ack;
//表示只确认了一个包,其它包已经被dupack确认过了
w->cumul_ack = tp->mss_cache;
} else {
/* delayed ack or cumulative ack,
* 表示被延迟的确认,或者结束Recovery的累积确认
*/
w->cumul_ack -= w->accounted;
w->accounted = ;
}
} w->snd_una = tp->snd_una; //记录当前的snd_una return w->cumul_ack;//返回此ACK确认的字节数
} /*
* TCP Westwood
* Here limit is evaluated as Bw estimation*RTTmin (for obtaining it
* in packets we use mss_cache). Rttmin is guaranteed to be >= 2
* so avoids ever returning 0.
*/
static u32 tcp_westwood_bw_rttmin(const struct sock *sk)
{//此函数在丢包后调用,根据带宽来设置拥塞窗口和慢启动阈值。
const struct tcp_sock *tp = tcp_sk(sk);
const struct westwood *w = inet_csk_ca(sk);
return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, );
} static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
{//westwood的"入口函数",其他函数都是通过这个函数调用的,
//不同与其他的TCP拥塞控制算法。
struct tcp_sock *tp = tcp_sk(sk);
struct westwood *w = inet_csk_ca(sk); switch (event) {
/* 处于快速路径时,用此函数更新w->bw_est和w->rtt_min */
case CA_EVENT_FAST_ACK:
westwood_fast_bw(sk);
break; /* 退出Recovery或CWR状态时,进行拥塞窗口和慢启动阈值设置*/
case CA_EVENT_COMPLETE_CWR:
tp->snd_cwnd = tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
break; //当RTO超时时,会先进行FRTO检测,这时可设置慢启动阈值,
//而拥塞窗口则设置为1.
case CA_EVENT_FRTO:
tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
/* Update RTT_min when next ack arrives */
//如果超时了,那么最小RTT可能不准确,需要重新设置
w->reset_rtt_min = ;
break; //处于慢速路径时,这时候的拥塞状态可能是CWR、Recovery、Loss等。
//必须采用westwood_acked_count()来统计此ACK确认的数据量。
//同时也进行w->bw_est和w->rtt_min的更新。
case CA_EVENT_SLOW_ACK:
westwood_update_window(sk);//更新带宽估计值
w->bk += westwood_acked_count(sk);//计算所收到ACK确认的数据量
update_rtt_min(w);//更新最小rtt
break; default:
/* don't care 对其它的事件则不做响应 */
break;
}
} /* Extract info for Tcp socket info provided via netlink. */
//通过netlink提供信息给tcp_socket
static void tcp_westwood_info(struct sock *sk, u32 ext,
struct sk_buff *skb)
{
const struct westwood *ca = inet_csk_ca(sk);
if (ext & ( << (INET_DIAG_VEGASINFO - ))) {
struct tcpvegas_info info = {
.tcpv_enabled = ,
.tcpv_rtt = jiffies_to_usecs(ca->rtt),
.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min),
}; nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
}
} static struct tcp_congestion_ops tcp_westwood = {
.init = tcp_westwood_init,
.ssthresh = tcp_reno_ssthresh,
.cong_avoid = tcp_reno_cong_avoid,
.min_cwnd = tcp_westwood_bw_rttmin,
.cwnd_event = tcp_westwood_event,
.get_info = tcp_westwood_info,
.pkts_acked = tcp_westwood_pkts_acked, .owner = THIS_MODULE,
.name = "westwood"
}; static int __init tcp_westwood_register(void)
{ //注册westwood算法
BUILD_BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE);
return tcp_register_congestion_control(&tcp_westwood);
} static void __exit tcp_westwood_unregister(void)
{ //注销westwood算法
tcp_unregister_congestion_control(&tcp_westwood);
} module_init(tcp_westwood_register);//westwood模块的入口函数
module_exit(tcp_westwood_unregister);//westwood模块的出口函数 MODULE_AUTHOR("Stephen Hemminger, Angelo Dell'Aera");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TCP Westwood+");

tcp westwood源代码分析的更多相关文章

  1. 转:RTMPDump源代码分析

    0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...

  2. 【转载】linux环境下tcpdump源代码分析

    linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02  CSDN博客 原文链接  http://blog.csdn.net/han_dawei/article/d ...

  3. linux环境下tcpdump源代码分析

    Linux 环境下tcpdump 源代码分析 韩大卫@吉林师范大学 tcpdump.c 是tcpdump 工具的main.c, 本文旨对tcpdump的框架有简单了解,只展示linux平台使用的一部分 ...

  4. Memcached源代码分析 - Memcached源代码分析之消息回应(3)

    文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...

  5. OpenStack_Swift源代码分析——Ring的rebalance算法源代码具体分析

    1 Command类中的rebalnace方法 在上篇文章中解说了,创建Ring已经为Ring加入设备.在加入设备后须要对Ring进行平衡,平衡 swift-ring-builder object.b ...

  6. nginx源代码分析--进程间通信机制 &amp; 同步机制

    Nginx源代码分析-进程间通信机制 从nginx的进程模型能够知道.master进程和worker进程须要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号, ...

  7. MonkeyRunner源代码分析之启动

    在工作中由于要追求完毕目标的效率,所以很多其它是强调实战.注重招式.关注怎么去用各种框架来实现目的.可是假设一味仅仅是注重招式.缺少对原理这个内功的了解,相信自己非常难对各种框架有更深入的理解. 从几 ...

  8. 【VS开发】【Live555-rtsp】RTSP服务器实例live555源代码分析

    原文地址:RTSP服务器实例live555源代码分析作者:mozheer 1. RTSP连接的建立过程 RTSPServer类用于构建一个RTSP服务器,该类同时在其内部定义了一个RTSPClient ...

  9. android-plugmgr源代码分析

    android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束.关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好.在这篇文章中,我 ...

随机推荐

  1. 十個必用的 Vim Plugin

    ◎ The NERD Tree 操作 Vim 時,通常都在 Terminal 底下作用,無法像一般的 GUI    應用程式可以以樹狀目錄來瀏覽檔案. The NERD Tree    是一將檔案目錄 ...

  2. Purpose of ContextLoaderListener in Spring

    The ApplicationContext is where your Spring beans live. The purpose of the ContextLoaderListener is ...

  3. SVN导出Maven项目

    1.从SVN检出项目 -> 作为工作空间中的项目检出 2.转换成Maven project 3.将Maven Project 转化成 Maven app 右击项目-> Properties ...

  4. sql server动态行列转换

    原文链接:https://www.cnblogs.com/gaizai/p/3753296.html sql server动态行列转换 一.本文所涉及的内容(Contents) 本文所涉及的内容(Co ...

  5. Linux shell 程序设计

    shell 程序设计 主要的学习内容包含基本思路,语法:变量.条件判断和程序控制,命令列表,函数,命令及执行,调试,grep命令和正则表达式,find命令 什么是shell 适用编写执行相对简单任务的 ...

  6. Java集合—Set(转载)

    Set集合中包含了三个比较重要的实现类:HashSet.TreeSet和EnumSet.本篇文章将重点介绍这三个类. 一.HashSet类 HashSet简介 HashSet是Set接口的典型实现,实 ...

  7. PSR-2 代码风格规范

    https://blog.csdn.net/qq_28602957/article/details/52248239 这篇规范是PSR-1(基本代码规范)的扩展和继承. 本规通过制定一系列规范化PHP ...

  8. ibatis打印sql

    ###显示SQL语句部分log4j.logger.com.ibatis=DEBUGlog4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUGl ...

  9. Xcode控制台命令

    命令 解释 break NUM 在指定的行上设置断点 bt 显示所有的调用栈帧,该命令可用来显示函数的调用顺序 clear 删除设置在特定源文件.特定行上的断点,其用法为:clear FILENAME ...

  10. php集成财付通支付接口

    <?phpif(!defined('DEDEINC')) exit('Request Error!');/** *财付通接口类 */class tenpay{ var $dsql; var $m ...