CUBIC TCP拥塞算法#优质参考_第1页
CUBIC TCP拥塞算法#优质参考_第2页
CUBIC TCP拥塞算法#优质参考_第3页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、TCP拥塞控制算法及Linux内核实现1. 引言借鉴内容# 由于Internet是一种基于Best-Effort服务的网络,传输控制协议TCP却能够在不可靠的互联网上提供可靠的服务,所以说TCP已经得到了大量的部署和使用并且统治着几乎全部的Internet数据流量。然而TCP协议的性能又在很大程度上由TCP拥塞控制算法决定,当今互联网上的算法又实在太多,如果想要专心研究几个算法还真不知道应该研究那些,不过有过研究称现在传统的AIMD算法已经不再是用得最多的算法了1。不过在研究中只是对前5000的服务器进行了一个并不一定准确的测定,笔者认为现在很多的很多服务器还是基于Linux操作系统,很多人并

2、不会对原本的算法进行修改也没有多大的必要,我们通过查看/proc/sys/net/ipv4/tcp_congestion_control可以发现现在的Linux内核默认是cubic算法,所以我笔者猜测之前的研究1虽然是基于真正的事实,但是毕竟是最大的服务器集群,那是属于一个很专业的系统,也就是说管理员很有可能在每个地方都尽量给出最好的方案,但是大多数普通的服务器并没有这个必要,也就是说那5000个流量最大的服务器集群并不能够真实地反应我们当今Internet上的算法部署情况。毫无疑问的是现在的服务器大多都是Linux内核,相信cubic以及一些别的Linux内核内置的算法在整个Internet

3、上占有的比率肯定大于之前的研究。本文并不会在具体的占有率上进行研究,只是谈及一下Linux内核2.6.36版本的TCP拥塞控制算法实现,同时会介绍一下Linux的TCP拥塞控制。 2. TCP拥塞控制简介我们知道现在的整个互联网体系结构是以IP协议为基础的,是一种基于无连接的端到端的报文传输服务,端到端传输的有点很多,但是有一个基本的问题就是需要自己来保证数据的可靠性。所以说TCP的拥塞控制对于整个Internet来说都是非常重要的,本文就将对Linux操作系统的拥塞控制算法进行一定的源码分析,更为深层次的分析笔者可能会在以后做一定的阐述。先来看一下TCP是如何保证数据的可靠传输的2,TCP的

4、设计其实非常容易理解的,TCP对所传输的数据都做了序号标记,序号按着字节数来增长,TCP的接收方在接到数据后发出一个确认(ACK)给对端,ACK里面包含一个序列号,这个序列号n表示序号在n之前的数据已经全部收到了,现在期待序号为n的数据到来。我们必须要知道的一个事实就是,主机发去网络上的任何一个数据包都有可能在网络上被丢弃,由于网络中路由器处理能力限制、链路错误等原因都会导致数据包的丢弃。如果ACK被丢弃了的话,那么就要靠重传机制了。TCP对发出去的数据包都保留有计时器,如果定时器到而确认还没有收到的情况下,TCP会对刚才发送的数据包进行重传。TCP使用确认和超时重传机制保障了数据的可靠性传输

5、。当网络中存在过多的报文时,网络的性能就会相应下降,这种现象就被称为拥塞。TCP的拥塞控制有很多的机制(慢启动、拥塞避免、快速重传、快速恢复等), 具体的一些工作方式在很多书籍论文中都已经有所阐述,本文将不再赘述。3. Linux源码概述作为黑客们技术和梦想的结晶,Linux无疑是这个世纪黑客们以及那些开源爱好者们最大的创举,有时候不禁感慨如果这个世界没有Linux或是Unix将是怎样,应该来说肯定会有别的系统来替代Linux的位置,但是现在,Linux在这么多年的发展,在世界的各个地方都布满了Linux的身影,尤其是这几十年随着Internet的迅速发展,Linux这样一个开源的操作系统更是

6、大发神威,因为其在Internet上的出色表现(稳定、可定制、免费等),现在的Linux操作系统已经成为Internet上最重要的操作系统,为世界的交流和互通提供了最基本的服务。既然Linux在现代社会和Internet占有这么重要的地位,那么毫无疑问的是这个系统上的任何一个设计,尤其是关于网络的设计对整个互联网而言都是非常重要的,笔者也是考虑到这个问题所以说选择Linux的源码来分析我们所探讨的主题。但是因为笔者时间并不宽裕,很多地方也没有深入去研究,所以说肯定还有很多需要提升的地方,待日后再返工。4. Linux源码分析一:基本数据结构和函数 Linux内核支持相当多种的TCP拥塞控制算法

7、,不过在内核2.6.19版本之后默认的算法调成了CUBIC算法。首先说说Linux内核拥塞控制算法实现的框架,Linux 下面介绍一下Linux内核实现拥塞控制的几个共同的数据结构或函数:1) inet_connection_sock是Linux内核拥塞控制实现相当重要的一个数据结构。由于这个数据结构实在太大,具体的定义可以参考include/inet/inet_connection_sock.h里面的定义,这里笔者就大概拿出几个比较重要的来说一下吧。首先是const struct tcp_congestion_ops *icsk_ca_ops,这个结构体指向的是一个包含大量的处理拥塞控制算法

8、的指针,结构体中还有一个是u32 icsk_ca_priv16,这里的作用是放置拥塞控制模块需要的变量控制,也就是算法运行过程中需要的那些常量都是保存在这里的,具体的赋值运行过程由于在代码里面也没有太多的注释所以很难理解深刻,需要注意的一点是Linux内核设定了一套算法注册和删除的体系。其实就是一个链表,把新注册的数据结构插在链表的第一位,连接建立的时候会把最新注册的算法数据结构赋给连接;当然我们也是可以调整算法顺序的,/proc/sys/net/ipv4/tcp_congestion_contril 就是干这个事的。2) Tcp_sock这个结构体是一个很重要的结构体,里面定义了相当多的和T

9、CP拥塞控制有关的,这个结构体非常大,具体的定义在include/linux/Tcp.h里面,下面大概介绍一下比较重要的几个参数:struct tcp_sock . u32 window_clamp ; /* 最大窗口值 */ u32 rcv_ssthresh ; /* 当前窗口阈值 */ u32 rcv_wnd ; /* 当前接收窗口大小 */ . /* snd_wll 记录发送窗口更新时,造成窗口更新的那个数据报的第一个序号。 * 它主要用于在下一次判断是否需要更新发送窗口。 */ u32 snd_wll ; /* 用于窗口更新的seq值 */ u32 snd_wnd ; /* 发送窗口的

10、大小,直接取值于来自对方的数据报的TCP首部 */ u32 max_window ; u32 snd_una ; . u32 snd_ssthresh ; /* 慢启动的阈值 */ u32 snd_cwnd ; /* 发送方拥塞窗口 */ /*表示在当前的拥塞控制窗口中已经发送的数据段的个数*/ u32 snd_cwnd_cnt ; /* 增长因子 */ u32 snd_cwnd_clamp ; /* 增长因子的最大值 */ . u32 mss_cache ; /* 有效mss值 */ u32 bytes_acked ; /* ACK的计数 */ . 3) Tcp_slow_start这个方法

11、是定义在net/ipv4/tcp_cong.c文件中的一种方法。当拥塞窗口小于慢启动阈值的时候就会启动。主要在RFC2581中定义。void tcp_slow_start(struct tcp_sock *tp)int cnt; /* 报文数目 */if (sysctl_tcp_abc & tp-bytes_acked mss_cache)return; /* ACK接收完毕 */if (sysctl_tcp_max_ssthresh 0 & tp-snd_cwnd sysctl_tcp_max_ssthresh)cnt = sysctl_tcp_max_ssthresh 1;/* 受限慢启动

12、 */elsecnt = tp-snd_cwnd;/* 指数递增 */if (sysctl_tcp_abc 1 & tp-bytes_acked = 2*tp-mss_cache)cnt bytes_acked = 0;tp-snd_cwnd_cnt += cnt;while (tp-snd_cwnd_cnt = tp-snd_cwnd) tp-snd_cwnd_cnt -= tp-snd_cwnd;if (tp-snd_cwnd snd_cwnd_clamp)tp-snd_cwnd+;4) 拥塞避免算法tcp_cong_avoid_ai定义于netipv4Tcp_cong.c,这个算法其实就

13、是判断一下当前发送拥塞窗口和一个传入参数w进行比较,如果发送计数器大于w且发送窗口没有到达阈值就自增,如果到达阈值了就置为0;如果发送计数器压根没有大于w的话计数器自增。5. Linux源码分析二:cubic算法 前面的介绍可能不是很清楚,如果想要更全面更清楚弄清楚这个流程可能需要更多的资料和代码研究,本文限于篇幅和笔者的水平只能尽力描述一下这一块的实现及主要的结构流程,那么我们接下来看一看默认算法cubic的代码实现。 首先和很多别的算法都一样,cubic算法会调用tcp_slow_start这个方法来处理slow start,内核中的slow start的实现机制是接收一个ack,snd_

14、cwnd就会加1,然后当cwnd大于设置的拥塞窗口阈值的时候就会进入拥塞避免状态。而在发送数据包的时候回判断这个值,在in_flight字段大于它的时候就会停止发包。因为cubic算法的设定是一直都通过慢启动来调整窗口大小的,当然,具体的这个算法特性本文不会讲得太多。 我们通过分析源码可以知道,在slow start的状态时发送拥塞窗口就是简单地每次加一,进入拥塞避免后,拥塞窗口的增大速度就会变慢很多3。 算法的核心状态控制代码定义在net/ipv4/Tcp_bic.c如下:static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32

15、in_flight)struct tcp_sock *tp = tcp_sk(sk);struct bictcp *ca = inet_csk_ca(sk);if (!tcp_is_cwnd_limited(sk, in_flight)/判断拥塞窗口是否达到限制return;if (tp-snd_cwnd snd_ssthresh)/决定下一步进入的状态tcp_slow_start(tp);else bictcp_update(ca, tp-snd_cwnd);tcp_cong_avoid_ai(tp, ca-cnt);这段代码主要是控制状态之间的转换,接下来会有一个tcp_is_cwnd_l

16、imited的函数来实现对拥塞窗口的检测,通过这个函数我们可以知道是否还能继续添加包。int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)const struct tcp_sock *tp = tcp_sk(sk);u32 left;if (in_flight = tp-snd_cwnd) /in_flight的计算很纠结,应该是和未确认数据包相关的一个参数return 1; /未发送的报文left = tp-snd_cwnd - in_flight;if (sk_can_gso(sk) & left * sysctl_tcp_tso_win_divisor snd_cwnd & left * tp-mss_cache sk_gso_max_size)return 1;return left = tcp_max_burst(tp);/所以返回的是1就是被限制,需要增加窗口这个算法的主要代码都在Tcp_cong.c、Tcp_cubic.c两个文件里面,有很多的相关的设置没有弄得很清楚,反正最后的拥塞避免处理就是tcp_cong_avoid_ai,这里决定是否增加拥塞窗口的值,否则增加snd_cwnd_cnt。大体的流程和主要函数就如上所述。6

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论