TCP拥塞控制算法内核实现剖析.docx

上传人:b****5 文档编号:8571375 上传时间:2023-01-31 格式:DOCX 页数:42 大小:43.56KB
下载 相关 举报
TCP拥塞控制算法内核实现剖析.docx_第1页
第1页 / 共42页
TCP拥塞控制算法内核实现剖析.docx_第2页
第2页 / 共42页
TCP拥塞控制算法内核实现剖析.docx_第3页
第3页 / 共42页
TCP拥塞控制算法内核实现剖析.docx_第4页
第4页 / 共42页
TCP拥塞控制算法内核实现剖析.docx_第5页
第5页 / 共42页
点击查看更多>>
下载资源
资源描述

TCP拥塞控制算法内核实现剖析.docx

《TCP拥塞控制算法内核实现剖析.docx》由会员分享,可在线阅读,更多相关《TCP拥塞控制算法内核实现剖析.docx(42页珍藏版)》请在冰豆网上搜索。

TCP拥塞控制算法内核实现剖析.docx

TCP拥塞控制算法内核实现剖析

TCP拥塞控制算法内核实现剖析

分类:

 LinuxKernel2011-12-0517:

10

内核版本:

2.6.37

主要源文件:

linux-2.6.37/net/ipv4/Tcp_cong.c 

一、RENO及拥塞控制算法基础

1.1RENO拥塞控制算法

===========================================================

structsock*sk和structtcp_sock*tp的转换

[cpp] viewplaincopy

1.在include/ linux/ Tcp.h中,  

2.static inline struct tcp_sock *tcp_sk(const struct sock *sk)   

3.{  

4.        return (struct tcp_sock *)sk ;  

5.}  

6.  

7.给出struct sock *sk,  

8.struct tcp_sock *tp = tcp_sk(sk) ;  

 

tcp_sock结构

[cpp] viewplaincopy

1.struct tcp_sock  

2.{  

3.       ...  

4. u32 window_clamp ; /* Maximal window to advertise */  

5. u32 rcv_ssthresh ; /* Current window clamp */  

6. u32 rcv_wnd ; /* Current receiver window */  

7.       ...  

8. /* snd_wll 记录发送窗口更新时,造成窗口更新的那个数据报的第一个序号。

 

9.  * 它主要用于在下一次判断是否需要更新发送窗口。

 

10.  */  

11. u32 snd_wll ; /* Sequence for window update */   

12. u32 snd_wnd ; /* 发送窗口的大小,直接取值于来自对方的数据报的TCP首部 */  

13. /* Maximal window ever seen from peer 记录来自对方通告的窗口的最大值 */  

14. /* First byte we want an ack for 发送窗口的左边沿 */  

15. u32 max_window ;  u32 snd_una ;   

16.        ...  

17. /* 

18.  * Slow start and congestion control 

19.  */  

20. u32 snd_ssthresh ; /* Slow start size threshold */  

21. u32 snd_cwnd ; /* Sending congestion window */  

22. /*表示在当前的拥塞控制窗口中已经发送的数据段的个数*/  

23. u32 snd_cwnd_cnt ; /* Linear increase counter */   

24. u32 snd_cwnd_clamp ; /* Do not allow snd_cwnd to grow above this */  

25.        ...  

26. u32 mss_cache ; /* cached effective mss , not including SACKS */  

27. u32 bytes_acked ; /* Appropriate Byte Counting - RFC3465 */  

28.       ...  

29.}  

拥塞避免算法关键部分

[cpp] viewplaincopy

1./* In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd ( or alternative w ) */  

2.void tcp_cong_avoid_ai(struct tcp_sock *tp , u32 w)  

3.{  

4.        if ( tp->snd_cwnd_cnt >= w) {  

5.                   if ( tp->snd_cwnd < tp->snd_cwnd_clamp)  

6.                        tp->snd_cwnd++ ;  

7.                   tp->snd_cwnd_cnt = 0 ;  

8.        } else {  

9.                   tp->snd_cwnd_cnt ++ ;  

10.        }                  

11.}  

12.EXPORT_SYMBOL_GPL(tcp_cong_avoid_ai) ;  

慢启动算法

tcp_max_ssthresh参数的含义

tcp_max_ssthresh参数是实现RFC3742时引入的,离现在已经有4年的时间了。

07年5月内核实现了这个RFC。

但是,tcp的这个参数在内核文档(ip-sysctl.txt)中找不到任何的说明。

慢启动阶段,就是当前拥塞窗口值比慢启动阈值(snd_ssthresh)小的时候,所处的阶段就叫做慢启动阶段。

当我们收到一个新的ACK时,则会调用tcp_slow_start()这个函数,并且为拥塞窗口增加1.

(Linux中拥塞窗口的值代表数据包的个数,而不是实际的发送字节数目。

实际可以发送的字节数等于可以发送的数据包个数*MSS。

直到慢启动阶段出现数据包的丢失。

而引入了tcp_max_ssthresh 这个参数后,则可以控制在慢启动阶段拥塞窗口增加的频度。

默认这个参数不打开,如果这个参数的值设置为1000,则当拥塞窗口值大于1000时,

则没收到一个ACK,并不再增加拥塞窗口一个单位了,而是约收到2个ACK才增加一个窗口单位。

注意:

收到2ACK并不是决定值!

需要根据当前的拥塞窗口值,tcp_max_ssthresh值进行判断。

参见tcp.txt(documentation/networking)

Thefollowingvariablesareusedinthetcp_sockforcongestioncontrol:

snd_cwndThesizeofthecongestionwindow

snd_ssthreshSlowstartthreshold.Weareinslowstartifsnd_cwndislessthanthis.

snd_cwnd_cntAcounterusedtoslowdowntherateofincreaseonceweexceedslowstartthreshold.

snd_cwnd_clampThisisthemaximumsizethatsnd_cwndcangrowto.

snd_cwnd_stampTimestampforwhencongestionwindowlastvalidated.

snd_cwnd_usedUsedasahighwatermarkforhowmuchofthecongestionwindowisinuse.Itisusedtoadjustsnd_cwnddownwhenthelinkislimitedbytheapplicationratherthanthenetwork.

1.void tcp_slow_start( struct tcp_sock *tp )  

2.{  

3. int cnt ; /* increase in packets */  

4.  

5./* RFC3465 :

 ABC slow start 

6. * Increase only after a full MSS of bytes is acked 

7. * 

8. * TCP sender SHOULD increase cwnd by the number of 

9. * previously unacknowledged bytes ACKed by each incoming  

10. * acknowledgment , provided the increase is not more than L 

11. */  

12. /* ack的数据少于MSS,tcp_abc默认关闭 */  

13. if ( sysctl_tcp_abc && tp->bytes_acked < tp->mss_cached )    

14.        return ;  

15.  

16./* 当前拥塞窗口值大于sysctl_tcp_max_ssthresh.限制拥塞窗口增长值*/ 

17. if ( sysctl_tcp_max_ssthresh >0 && tcp->snd_cwnd >sysctl_tcp_max_ssthresh)  

18.        cnt = sysctl_tcp_max_ssthresh >> 1 ; /* limited slow start */  

19. else   

20.        cnt = tp->snd_cwnd ; /* exponential increase */  

21.  

22./* RFC3465 :

 ABC 

23. * We MAY increase by 2 if discovered delayed ack   

24. */  

25./* 如果接收方启用了延时确认,此时收到的确认代表两个MSS数据报*/  

26.if ( sysctl_tcp_abc >1 && tp->bytes_acked >= 2*tp->mss_cache )   

27.        cnt <<= 1 ;  

28.  

29.tp->bytes_acked = 0 ;   

30.tp->snd_cwnd_cnt += cnt ; /* 此时snd_cwnd_cnt等于snd_cwnd或2*snd_cwnd */  

31.

32./*最多增加1/2sysctl_tcp_max_ssthresh字节。

也就是说,至少2个ACK才能让拥塞窗口增加1.*/

33. while( tp->snd_cwnd_cnt >= tp->snd_cwnd ) {   

34.        tp->snd_cwnd_cnt -= tp->snd_cwnd ;  

35.        if( tp->snd_cwnd < tp->snd_cwnd_clamp )  

36.                tp->snd_cwnd++ ;  

37. }  

38.}  

39.EXPORT_SYMBOL_GPL( tcp_slow_start ) ;  

1.2拥塞控制算法基础

1.2.1代表拥塞算法的结构体

1.#define TCP_CA_NAME_MAX 16

2.struct tcp_congestion_ops {  

3.        struct list_head list ;  

4.        unsigned long flags ;  

5.        /* initialize private data (optional) */  

6.        void (*init) (struct sock *sk) ;  

7.        /* cleanup private data (optional) */   

8.        void (*release) (struct sock *sk) ;  

9.        /* return slow start threshold (required) */  

10.        u32 (*ssthresh) (struct sock *sk) ;  

11.        /* lower bound for congestion window (optional) */  

12.        u32 (*min_cwnd) (const struct sock *sk) ;  

13.        /* do new cwnd calculation (required) */  

14.        void (*cong_avoid) (struct sock *sk , u32 ack , u32 in_flight ) ;  

15.        /* call before changing ca_state (optional) */  

16.        void (*set_state) (struct sock *sk , u8 new_state) ;  

17.        /* call when cwnd event occurs (optional) */  

18.        void (*cwnd_event) (struct sock *sk , enum tcp_ca_event ev) ;  

19.        /* new value of cwnd after loss (optional) */  

20.        u32 (*undo_cwnd) (struct sock *sk) ;  

21.        /* hook for packet ack accounting (optional) */  

22.        void (*pkts_acked) (struct sock *sk , u32 num_acked , s32 rtt_us) ;  

23.        /* get info for inet_diag (optional) */  

24.        void (*get_info) (struct sock *sk , u32 ext , struct sk_buff *skb) ;  

25.        char name[TCP_CA_NAME_MAX] ;  

26.        struct module *owner ;  

27.}  

 

在Tcp_cong.c中,有全局变量:

intsysctl_tcp_max_ssthresh=0;

/*defineDEFINE_SPINLOCK(x)spinlock_tx=__SPIN_LOCK_UNLOCKED(x)*/

staticDEFINE_SPINLOCK(tcp_cong_list_lock);

staticLIST_HEAD(tcp_cong_list);//tcp拥塞控制算法链表,其元素为tcp_congestion_ops

/*

 BUG_ON();如果BUG_ON中的条件为真就调用BUG,它输出一些信息,然后调用panic函数挂起系统。

 char*strncpy(char*dest,char*src,size_tn);

 它与strcpy不同之处在于复制n个字符,而不是把所有的字符拷贝(包括结尾'\0')。

  当src的长度小于n时,dst内的未复制空间用'\0'填充。

否则,复制n个字符到dst,没有加'\0'。

这里就要注意在字符串dst结尾处理加'\0'的情况了。

 rcu_read_lock()//读者在读取由RCU保护的共享数据时使用该函数标记它进入读端临界区。

 rcu_read_unlock()//该函数与rcu_read_lock配对使用,用以标记读者退出读端临界区。

*/

 

1.2.2对拥塞控制算法的一些操作(读写增减注册等)

[cpp] viewplaincopy

1./* Get current default congestion control */  

2.void tcp_get_default_congestion_control( char *name )  

3.{  

4.        struct tcp_congestion_ops *ca ;  

5.        /* We will always have reno */  

6.        BUG_ON( list_empty( &tcp_cong_list) ) ;  

7.  

8.        rcu_read_lock( ) ;  

9.        ca = list_entry( tcp_cong_list . next , struct tcp_congestion_ops , list ) ;  

10.        strncpy( name , ca->name , TCP_CA_NAME_MAX ) ;  

11.        rcu_read_unlock( ) ;  

12.}  

 

structsock——representationofsockets

 structinet_sock——representationofINETsockets

 structinet_connection_sock——INETconnectionorientedsockets

 structtcp_sock——tcpsockets

 以上几种socket越分越细,比如inet_connection_sock是在inet_sock上的扩展,具有自己特有的属性。

 tcp_sock是TCP协议专用的一个socket表示,它是在structinet_connection_sock基础进行扩展,主要是增加了滑动窗口协议,避免拥塞算法等一些TCP专有属性。

 

[cpp] viewplaincopy

1.struct inet_connection_sock {  

2.        ...  

3.        // Pluggable congestion control hook  

4.        const struct tcp_congestion_ops *icsk_ca_ops ;   

5.        ...  

6.  

7.        u32 icsk_ca_priv[16] ;  

8.#define ICSK_CA_PRIV_SIZE (16*sizeof(u32))  

9.}  

 

举例:

//有一个初始化了得structsock*sk

structinet_connection_sock*icsk=inet_csk(sk);

printk(KERN_INFO"%s",icsk->icsk_ca_ops->name);//当前连接拥塞控制算法名称

 

1.struct inet_sock {  

2.        ...  

3.        /* Socket demultiplex comparisons on incoming packets */  

4.        __be32 inet_daddr ;  

5.        __be16 inet_dport ;  

6.        __be32 inet_saddr ;  

7.        __be16 inet_sport ;  

8.        __be16 inet_num ; // local port   

9.        __be32 inet_rcv_saddr ; // Bound local IPv4 addr  

10.        ...  

11.}  

 

1./* Built list of non-restricted congestion control values*/  

2.void tcp_get_allowed_congestion_control( char *buf , size_t maxlen)  

3.{  

4.        struct tcp_congestion_ops *ca ;  

5.        size_t offs = 0 ;  

6.        *buf = '\0' ; //有必要?

  

7.         rcu_read_lock() ;  

8.        list_for_each_entry( ca , &tcp_cong_list , list ) {  

9.                if( !

( ca->flags & TCP_CONG_NON_RESTRICTED)) //排除有限制的。

限制和非限制区别?

  

10.                         continue;  

11.                offs += snprintf( buf+offs , maxlen-offs , "%s%s" , offs == 0?

"" :

 " " , ca->name) ;  

12.        }  

13.        rcu_read_unlock() ;  

14.}  

1./* Simple linear search , don't expect many entries!

 */  

2.static struct tcp_congestion_ops*tcp_ca_find( const char *name)  

3.{  

4.        struct tcp_congestion_ops *e ;  

5.        list_for_each_entry_rcu( e , &tcp_cong_list , list ) {  

6.                if( strcmp(e->name , name)==0)  

7.                        return e ;  

8.         }  

9.         return NULL ;  

10.}  

 

1./* 

2. * Attach new congestion control algorith

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1