
TCPIP协议
文章平均质量分 81
redwingz
这个作者很懒,什么都没留下…
展开
-
TCP绑定套接口链表
内核中全局变量tcp_hashinfo的成员bhash保存有全局的bind套接口。bhash是以哈希值为索引的数组,其中inet_bhashfn函数负责依据端口号和命名空间生成哈希值。每个数组元素包含一个哈希值相同的inet_bind_bucket结构组成的链表(chain链表)。struct inet_hashinfo tcp_hashinfo;struct inet_hashinfo { ... /* Ok, let's try this, I give up, we do n原创 2021-03-09 21:40:21 · 832 阅读 · 0 评论 -
命名空间接口序号dev_base_seq
网络命名空间初始化时,将序号dev_base_seq赋值为1。static __net_init int setup_net(struct net *net, struct user_namespace *user_ns){ /* Must be called with pernet_ops_rwsem held */ const struct pernet_operations *ops, *saved_ops; int error = 0; LIST_HEAD(net原创 2021-01-25 21:30:50 · 441 阅读 · 0 评论 -
TCP合法RST报文
RESET报文的接收和检查处理。客户端握手阶段对于TCP客户端,在发送完SYN报文之后,如果接收到的回复报文同时设置了ACK和RST标志,在检查完ACK的合法性之后,处理RST标志,关闭套接口。对于ACK确认序号,其应当大于第一个未确认序号(snd_una),并且,确认序号不应大于未发送数据的序号(snd_nxt)。通常情况下ACK确认序号应当等于snd_una加一(SYN占用一个序号),但是,如果SYN报文中带有数据(例如:TFO),ACK确认序号会更大。以上情况向对端发送reset报文,但是,如果原创 2020-12-12 20:33:14 · 2518 阅读 · 0 评论 -
TCP复位报文的发送
内核发送reset报文的函数为tcp_v4_send_reset,如下其赋值给了tcp_request_sock_ops结构的成员send_reset。struct request_sock_ops tcp_request_sock_ops __read_mostly = { .family = PF_INET, ... .send_reset = tcp_v4_send_reset,监听套接口不存在如下tcp_v4_rcv函数中,__inet_lookup_原创 2020-12-10 21:41:10 · 2163 阅读 · 1 评论 -
TCP-Westwood拥塞算法
TCP-Westwood在TCP-Reno的基础上增强了窗口控制和退避处理,例如,TCPW发送端监控ACK报文的接收速率,进而估算当前连接可达到的数据发送速率(可用带宽)。当发送端检测到丢包时(超时或者3个重复ACK),发送端根据估算的发送速率设置拥塞窗口大小(cwnd)和慢启动阈值(ssthresh)。不同于TCP-Reno的窗口减半处理,TCP-Westwood避免太过保守的减低窗口操作,TCP-Westwood称此为:Faster-Recovery。与TCP-Reno相比,TCP-Westwood更适原创 2020-06-30 22:08:37 · 3587 阅读 · 0 评论 -
TCP-Hybla拥塞算法
TCP Hybla算法的改进是对于RTT较长的连接(例如卫星和无线网络)可获得与参考TCP连接(如,有线网络)相同的瞬时发送速率B(t)。TCP的发送速率计算如下(W(t)表示t时刻的发送窗口值):B(t)=W(t)/RTT(1)\tag{1} B(t)=W(t)/RTTB(t)=W(t)/RTT(1)对于传统TCP,发送窗口计算如下:W(t)={2t/RTT if 0≤t<tγ,SSt−tγRTT+γ if t>tγ,CA(2)\tag{2}原创 2020-06-20 21:49:40 · 2662 阅读 · 1 评论 -
TCP-Reno拥塞算法
经典的Reno算法实现了三个拥塞函数,如下所示:struct tcp_congestion_ops tcp_reno = { .flags = TCP_CONG_NON_RESTRICTED, .name = "reno", .owner = THIS_MODULE, .ssthresh = tcp_reno_ssthresh, .cong_avoid = tcp_reno_cong_avoid, .undo_cwnd原创 2020-06-16 22:30:12 · 7006 阅读 · 0 评论 -
H-TCP拥塞算法
根据对AIMD拥塞算法的观察,对于传统网络,增加值α应当足够小,以便于同传统TCP拥塞算法(Reno/NewReno)相兼容;而对于高速和长距离(high-speed and long distance)网络,可增大α的值,以便获取额外的带宽。基于以上判断,H-TCP通过动态的调整α和β的值,来达到合理利用高速长距离网络的带宽,而又可在传统网络中与标准TCP保持友善性的目的。在高速模式下,增长参数α的值等于αH(Δ)\alpha^{H}(\Delta )αH(Δ).在低速模式下,增长参数alpha的值等于原创 2020-06-15 22:04:01 · 1587 阅读 · 0 评论 -
TCP客户端端口号选择
如下函数inet_hash_connect,如果没有指定绑定的接口,在发起连接的时候,由函数inet_sk_port_offset先选择一个端口偏移量(port_offset),函数__inet_hash_connect负责绑定端口。int inet_hash_connect(struct inet_timewait_death_row *death_row, struct sock *sk){ u32 port_offset = 0; if (!inet_sk(sk)->ine原创 2020-06-10 22:03:37 · 3602 阅读 · 0 评论 -
TCP监听端口选择
内核提供了两个PROC文件可以控制套接口使用的端口号范围,其中文件ipv4_local_port_range定义了可使用的端口范围;文件ip_local_reserved_ports定义了保留的端口范围。static struct ctl_table ipv4_net_table[] = { { .procname = "ip_local_port_range", .maxlen = sizeof(init_net.ipv4.ip_local_ports原创 2020-06-09 23:32:47 · 4865 阅读 · 0 评论 -
传统TCP(Reno)拥塞响应函数
TCP拥塞响应函数指吞吐与丢包率之间的一个关系,传统Reno-TCP执行以下两个操作:1)将丢包视为网络发生了拥塞,将拥塞窗口降低一半;2)在拥塞避免阶段,每个RTT周期,拥塞窗口增加1。以上两者决定了在丢包率和平均吞吐之间形成了一个简单的关系,这里的丢包率和吞吐都是指的一个稳定的状态值,不考虑丢包率急剧变化的情况。由于现实中传统TCP实现的一些具体情况,导致其对拥塞的反应比理论上要缓慢,例如较长的超时时间、SlowStart恢复算法、发送窗口限制以及延时ACK等,都将导致实际的窗口增长相比理论上要慢,所原创 2020-06-06 23:45:24 · 2035 阅读 · 1 评论 -
TCP套接口选择
在TCP接收函数tcp_v4_rcv中,由__inet_lookup_skb执行报文所属套接口的查找任务。int tcp_v4_rcv(struct sk_buff *skb){ int sdif = inet_sdif(skb); th = (const struct tcphdr *)skb->data; iph = ip_hdr(skb);lookup: sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tc原创 2020-06-02 21:25:00 · 1453 阅读 · 0 评论 -
Scalable TCP拥塞算法
Scalable TCP(STCP)拥塞控制算法,在每个RTT周期内,如果没有发生拥塞,将在接收到每个ACK报文后,将拥塞窗口增加0.01(a值)。cwnd = cwnd + 0.01如果在一个RTT周期内第一次检测到拥塞发生,将拥塞窗口减低1/8倍(b值),在同一个RTT周期仅降低一次拥塞窗口。cwnd = cwnd − [0.125 * cwnd]使用STCP算法的发送端在任一发送速率下,经过大约70个RTT可实现速率的翻倍,其窗口更新算法具有可扩展性。如下,以窗口减半为例,即1/2cw原创 2020-05-30 23:52:47 · 839 阅读 · 0 评论 -
TCP-BIC Binary Increase Congestion算法
具体算法参见文档:Binary Increase Congestion Control for Fast,Long Distance Networks。BIC预设参数fast_convergence - 是否启用快速收敛。启用的话将会修正选择的最大拥塞窗口,尽快达到合理的窗口值。low_window - 只有当拥塞窗口大于此值时,BIC算法才开始生效。默认值为14,拥塞窗口小于此值时,采用传统的Reno TCP拥塞算法控制窗口。max_increment - 在二分查找增长拥塞窗口时,可增长的最大限原创 2020-05-25 23:41:23 · 1311 阅读 · 0 评论 -
SlowStart阶段拥塞窗口增长
慢启动阶段的拥塞窗口增长函数tcp_slow_start如下,拥塞窗口以报文数量表示,参数acked表示当前ACK报文确认的数据包数量。如果拥塞窗口增加acked数量之后小于慢启动阈值ssthresh,使用二者相加结果作为新的拥塞窗口值。内核没有使用RFC3465中定义的ABC(Appropriate Byte Counting)算法,其最初设计的是针对按照字节表示拥塞窗口的系统。内核中规定了对数据报文的确认必须是对整个报文的确认,也可抵御ACK Division攻击。u32 tcp_slow_start原创 2020-05-20 23:42:48 · 1106 阅读 · 0 评论 -
TCP快速恢复算法PRR
PRR算法(Proportional Rate Reduction)决定在丢包恢复(Loss Recovery)期间,对应于每个ACK报文,可发送的报文数量。目的是:1)快速平稳的从Loss中恢复;2)恢复之后拥塞窗口收敛与ssthresh。主要是为了解决Linux内核之前采用的恢复算法Rate-halving存在的一些弊端:在恢复阶段,为防止burst发送,内核将拥塞窗口设置为pipe+1,然而,如果由于应用程序没有数据可发送,最早将导致拥塞窗口降低为1,即使仅丢失了一个报文。在恢复之后,将拥塞窗口原创 2020-05-19 22:57:32 · 3785 阅读 · 0 评论 -
TCP混合慢启动
混合慢启动(Hybrid Slow Start)使用二个信息来决定SlowStart阶段到拥塞避免阶段(Congestion Avoidance)的转换,一是ACK Train的长度;二是报文延迟的增长。ACK Train的长度为在一个RTT周期内,紧密相邻的ACK报文到达的时间间隔之和,内核默认间隔不大于2ms的一系列ACK报文为ACK Train。每个RTT周期,计算一次ACK Train长度,与估算的最小路径发送延迟进行对比,SlowStart阶段报文延迟的增长也可能意味着路径中的瓶颈路由器已经发生原创 2020-05-18 22:42:20 · 1904 阅读 · 3 评论 -
TCP传输速率估算
如下公式,带宽取值为计算得出的数据发送速率与接收ACK速率两者之间的较小值。通常情况下,发送速率(send_rate)将大于ACK接收速率(ack_rate),但是,在面对ACK压缩等的情况下,将导致ACK接收速率意外的增大,此时,带宽应选取发送速率(send_rate)。 send_rate = #pkts_delivered/(last_snd_time - first_snd_time) ack_rate = #pkts_delivered/(last_ack_time - firs原创 2020-05-13 23:22:10 · 8332 阅读 · 1 评论 -
RACK与重复ACK
默认情况下sysctl_tcp_recovery的值为1(TCP_RACK_LOSS_DETECTION),也可通过PROC文件:/proc/sys/net/ipv4/tcp_recovery进行修改,如果设置了标志位TCP_RACK_NO_DUPTHRESH,表明RACK不使用重复ACK阈值(DupAck Threshold),默认未设置此标志。#define TCP_RACK_LOSS_DETECTION 0x1 /* Use RACK to detect losses */#define TCP原创 2020-05-11 20:45:25 · 1112 阅读 · 0 评论 -
Reno报文乱序与快速重传
基础内容参见上一篇: SACK报文乱序级别reorderingReno乱序调整首先看一下,在Reno算法中,对重复ACK数量的修正。如果sacked_out表示的DupAck数量与丢失报文数量之和,大于发出去的总报文数量,可能是因为网络自身的报文复制所导致,包括对数据报文的复制或者对ACK报文的复制,这时候需要调整DupAck数量值。static bool tcp_limit_reno_sacked(struct tcp_sock *tp){ u32 holes; holes =原创 2020-05-09 23:28:59 · 786 阅读 · 0 评论 -
SACK报文乱序级别reordering
内核默认的初始乱序级别为TCP_FASTRETRANS_THRESH(3),最大值为300。即当接收到三个重复ACK报文时,触发快速重传。#define TCP_FASTRETRANS_THRESH 3static int __net_init tcp_sk_init(struct net *net){ net->ipv4.sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH; net->ipv4.sysctl_tcp_retra原创 2020-05-08 20:45:30 · 1326 阅读 · 0 评论 -
TCP套接口丢失与重传报文线索
TCP套接口丢失与重传报文线索由变量lost_skb_hint与retransmit_skb_hint所表示。丢失报文线索变量lost_skb_hint记录重传队列中上一次标记丢失报文的位置,其自身对应的skb不一定为丢失报文,也可能是SACK确认报文。如下函数tcp_mark_head_lost,其仅在sack恢复算法中使用,用于将重传队列中的相应报文标记为丢失状态,标记为丢失状态的报文数量...原创 2020-05-06 20:54:32 · 991 阅读 · 0 评论 -
TCP回撤拥塞状态
由于网络路径的变化或者延时的突然增加等,引发乱序并触发快速恢复或者RTO超时,TCP将进入TCP_CA_Recovery或者TCP_CA_Loss拥塞状态,如果随后检测到报文并没有丢失,TCP将撤销拥塞状态,恢复到之前的拥塞状态。拥塞撤销初始化其一,在进入快速恢复阶段时,不管是基于Reno或者SACK的快速恢复,还是RACK触发的快速恢复,都将使用函数tcp_enter_recovery进入T...原创 2020-05-02 21:35:50 · 1323 阅读 · 0 评论 -
时间排序的SACK未确认报文链表
内核实现的时间排序的未确认报文链表(time-sorted sent but un-SACKed skbs),用于加速RACK算法的处理。tsorted链表初始化首先是位于套接口的初始化函数tcp_init_sock中,初始化此链表tsorted_sent_queue。void tcp_init_sock(struct sock *sk){ struct inet_connecti...原创 2020-05-01 23:53:32 · 656 阅读 · 0 评论 -
Reno与RACK对丢失/重传报文的标记
主要涉及到两个变量,一是重传报文计数retrans_out;二是丢失报文计数lost_out。RACK丢失报文判断如下函数tcp_rack_detect_loss,如果报文具有丢失标志(TCPCB_LOST),但是没有重传标志(TCPCB_SACKED_RETRANS),表明丢失报文还未进行重传,不进行重复处理。否则,在RACK确认报文已经丢失之后,由函数tcp_mark_skb_lost进行...原创 2020-04-29 21:05:10 · 755 阅读 · 0 评论 -
TCP连接建立之后的SACK选项解析
这几天有点犯糊涂,搞不清楚连接建立之后,SACK选项的解析在什么地方处理。内核中唯一能解析SACK选项的函数就是tcp_parse_options,但是就找不到tcp_rcv_established函数在哪里调用它。这里犯了一个错误,一直以为tcp_validate_incoming函数仅是验证报文,其中的tcp_fast_parse_options只是快速解析timestamps选项。stat...原创 2020-04-28 19:22:28 · 536 阅读 · 0 评论 -
TCP报文丢失判断
主要介绍下RTO超时、NewReno、SACK以及RACK等情况下的报文丢失判断。RTO超时标记丢失报文在RTO超时处理中,套接口进入TCP_CA_Loss状态,由函数tcp_timeout_mark_lost标记套接口丢失报文。/* Enter Loss state. */void tcp_enter_loss(struct sock *sk){ tcp_timeout_mar...原创 2020-04-26 22:28:33 · 3637 阅读 · 0 评论 -
TCP零窗口探测
TCP零窗口探测用于获取触发对端的窗口更新报文,防止在窗口更新报文丢失之后,导致的死循环。其也有助于本端Qdisc满或者数据被发送节奏(Pacing)阻止导致的发送停滞。窗口探测开启在TCP报文发送函数tcp_write_xmit的处理中,如果最终未能发送任何报文,而且网络中报文为空(packets_out),套接口的发送队列中有数据,将返回true。造成此情况可能是由于惰性窗口综合征(SWS...原创 2020-04-22 19:55:24 · 6478 阅读 · 0 评论 -
TCP连接保活检测Keepalive
TCP连接的keepalive定时器用于定期检测连接是否正常。Keepalive初始化默认情况下Keepalive每两个小时触发一次,触发之后,最多发送9次探测报文,每个报文的间隔为75秒钟。即在9次探测都没有接收到对端的回复之后,认为连接已经断开。#define TCP_KEEPALIVE_TIME (120*60*HZ) /* two hours */#define TCP_KEEP...原创 2020-04-21 20:46:50 · 1294 阅读 · 0 评论 -
TCP用户超时(UTO)
Linux内核提供了可设置的TCP用户超时时长(TCP User Timeout),其控制发送的未确认数据可保持多长时间,之后强制关闭连接。但是,内核不支持RFC5482定义的TCP UTO选项(User Timeout Option),不会将此设置通告给对端,其为本地超时时长。UTO用户接口应用层可通过setsockopt选项TCP_USER_TIMEOUT设置超时时长,内核将其保存在ics...原创 2020-04-18 23:32:58 · 3758 阅读 · 0 评论 -
TCP Thin-Stream连接
Thin-stream属性,意味着应用程序以很低的速率发送数据,致使TCP等传输协议的重传机制不能有效的运行。一些场景(类似于在线游戏,控制系统,股票交易等)中,用户体验取决于数据的发送时延,报文丢失对于服务质量来说是灾难性的。极大的时延是由于TCP依赖于应用程序新的报文的发送,进而通过快速重传来启动丢失报文的重传,而不用等待较长时间的RTO超时。以上提到的时间敏感的交互应用,通常是会产生thi...原创 2020-04-16 22:47:56 · 1169 阅读 · 0 评论 -
TCP的RTO值估算
大致介绍一下Linux内核实现的RTO值计算方式,以及与RFC6298的不同之处。RTT估算static void tcp_rtt_estimator(struct sock *sk, long mrtt_us){ struct tcp_sock *tp = tcp_sk(sk); long m = mrtt_us; /* RTT */ u32 srtt = tp-&...原创 2020-04-12 21:39:20 · 2204 阅读 · 0 评论 -
TCP空闲连接的重启动
在TCP连接空闲一段时间之后,发送端再次开启发送时,可能导致大量的数据发送到网络中。由于一段空闲时间后,TCP发送端不能再使用ACK时钟发送新报文到网络中,所以,可能线速发送一整拥塞窗口的数据,容易造成网络拥塞,而且,网络状况可能已经改变。因此,内核中在空闲时间超过RTO之后,将使用慢启动恢复发送。空闲检查在空闲检查函数中,如果内核未打开在空闲之后启用慢启动的功能,即tcp_slow_star...原创 2020-04-09 21:39:58 · 1083 阅读 · 0 评论 -
TCP拥塞窗口验证
如果在一个RTO时长内,拥塞窗口没有被完全的使用,TCP发送端将减小拥塞窗口。因为此时TCP发送端的拥塞窗口可能并非当前的网络状况,所以发送端应减小拥塞窗口。根据RFC2861,ssthresh应设置为其当前值与3/4倍的拥塞窗口值两者之间的最大值,而拥塞窗口设置为实际使用的量和当前拥塞窗口值之和的一半。在如下发送函数tcp_write_xmit中,如果实际执行了发送报文操作,即sent_pkt...原创 2020-04-08 21:20:36 · 1148 阅读 · 0 评论 -
SACK Reneging
TCP发送端不能够清除SACK序号块确认的数据,因为接收端很可能由于内存压力等原因,删除乱序队列中SACK确认过的报文。发送端重传队列中的报文只有在接收到ACK报文的Acknowledge序号字段确认之后,才能移除队列和释放。接收端丢弃OFO报文如下在检测的已用接收缓存大于套接口总的接收缓存sk_rcvbuf时,并且接收缓存已不能够再扩大,最后的措施就是释放乱序报文队列,参见函数tcp_pru...原创 2020-04-04 10:28:43 · 926 阅读 · 0 评论 -
SACK选项及生成
SACK功能由两个TCP选项组成,分别为SACK_PERMITTED和SACK选项。前者用于协商SACK能力,仅可出现在设置了SYN标志的报文中,如下为其格式。 TCP Sack-Permitted Option: Kind: 4 +---------+---------+ | Kind=4 | Length=2| +---------+-------...原创 2020-04-02 21:31:42 · 2720 阅读 · 0 评论 -
SACK压缩
变量tcp_comp_sack_nr定义在接收到连续的乱序报文时,可压缩的最大SACK回复报文数量,即低于tcp_comp_sack_nr值时,延时回复对端ACK报文。但是,前TCP_FASTRETRANS_THRESH(3)数量的乱序报文,要立即回复ACK报文,以帮助对端完成快速重传。Compressed-ACK初始化static int __net_init tcp_sk_init(str...原创 2020-03-31 21:29:31 · 1078 阅读 · 0 评论 -
Forward-RTO超时确认
虚假的重传超时将导致TCP性能的降低,因为这将发送不必要的重传报文。Forward-RTO是一种用于检测虚假重传超时的一种算法,F-RTO仅针对发送端,其不需要任何TCP选项的支持。在超时重传第一个未确认的报文之后,TCP发送端的F-RTO检测回来的ACK报文,来确定此次超时是否是虚假的。进而,决定是否发送新的报文,或是重传未确认报文。F-RTO初始化如下内核函数tcp_sk_init,将sy...原创 2020-03-29 21:53:21 · 687 阅读 · 2 评论 -
Tail Loss Probe实现
Tail loss probe (TLP)利用RACK减少RTO的发生,TLP触发快速恢复以修复末端丢包,否则只能由之后的RTO来修复。在原始报文发送之后,TLP将在1到2倍的RTT时间内发送探测数据报文,探测报文可以是新的、之前非发送过的报文,或者重传SND.NXT序号之前已经发送过的报文。探测报文的发送旨在激起对端的反馈,例如ACK报文,这样RACK就可以发起快速重传,而不用等待RTO超时。...原创 2020-03-28 22:37:00 · 1609 阅读 · 0 评论 -
PAWS检查
PAWS(Protection Against Wrapped Sequences)功能基于TCP的Timestamps选项实现,用于拒绝接收到的过期的重复报文。PAWS假设每个报文都携带有TSopt选项数据,其中的时间戳TSval保持单调递增,所有,当接收到一个报文其TSval值小于之前在此连接中接收到的时间戳(ts_recent),即认定此报文为过期报文,将其丢弃。由于TSval时间戳为32...原创 2020-03-22 07:34:50 · 2324 阅读 · 0 评论