当前位置:网站首页>TCP协议之《自动阻塞CORK控制》
TCP协议之《自动阻塞CORK控制》
2022-08-10 03:26:00 【程序员扫地僧】
当应用程序在使用write或者sendmsg系统调用连续的发送少量数据包时,内核试图将这些小包尽可能的合并在一起发送,以降低总得数据包量。得以实现的前提是,至少有一个同数据流的之前数据包正在Qdisc队列或者网络设备的队列中等待发送。以下详细解释这一点。
一、初始化
在TCP协议的初始化函数tcp_sk_init中,将网络命名空间的sysctl_tcp_autocorking设置为1,打开自动阻塞功能。可通过查看PROC文件系统的/proc/sys/net/ipv4/tcp_autocorking获得当前设置值,也可进行修改,置零关闭此功能。
static int __net_init tcp_sk_init(struct net *net)
{
net->ipv4.sysctl_tcp_autocorking = 1;
}
$ cat /proc/sys/net/ipv4/tcp_autocorking
1
二、自动阻塞判断
核心函数tcp_should_autocork,这里要进行四个判断已确定是否执行自动阻塞autocork。大致解释如下:如果当前SKB的数据还未填满(size_goal为MSS整数倍),并且Qdisc或者网络设备队列中有数据包,将不发送当前的SKB而是CORK住。原因是,Qdisc或者NIC队列中的数据包马上就要发送,当发送完成中断到来前,还可将用户随后要发送的数据合并到当前CORK住的SKB中。中断发生之后,TSQ功能负责数据包的继续发送。
最后一个判断,意味着如果Qdisc或者NIC队列中仅有ACK报文,autocorking将不能使用,可能会在处理完成ACK报文之后,发送完成中断被延后,将造成当前数据包的延迟。套接口变量sk_wmem_alloc表示该套接口提交到网络层发送的数据总长度,由于ACK报文没有数据部分,所以理论上其在提交发送时sk_wmem_alloc并不增加,但是由于某种原因增加2。
static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb, int size_goal)
{
return skb->len < size_goal &&
sock_net(sk)->ipv4.sysctl_tcp_autocorking &&
skb != tcp_write_queue_head(sk) &&
refcount_read(&sk->sk_wmem_alloc) > skb->truesize;
}
三、判断执行流程
内核在函数tcp_push中调用tcp_should_autocork判断,如果autocork成立,将设置TCP套接口的TSQ_THROTTLED标志。随后再次判断sk_wmem_alloc的值是否依然大于SKB的truesize,为真直接返回,否则说明发送中断已经发生了,autocork失效,进行数据的发送__tcp_push_pending_frames。
static void tcp_push(struct sock *sk, int flags, int mss_now, int nonagle, int size_goal)
{
skb = tcp_write_queue_tail(sk);
if (!skb)
return;
if (!(flags & MSG_MORE) || forced_push(tp))
tcp_mark_push(tp, skb);
tcp_mark_urg(tp, flags);
if (tcp_should_autocork(sk, skb, size_goal)) {
if (!test_bit(TSQ_THROTTLED, &sk->sk_tsq_flags)) { /* avoid atomic op if TSQ_THROTTLED bit is already set */
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING);
set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);
}
/* It is possible TX completion already happened before we set TSQ_THROTTLED. */
if (refcount_read(&sk->sk_wmem_alloc) > skb->truesize)
return;
}
if (flags & MSG_MORE)
nonagle = TCP_NAGLE_CORK;
__tcp_push_pending_frames(sk, mss_now, nonagle);
}
TCP数据发送函数tcp_transmit_skb如下,以上的函数__tcp_push_pending_frames将调用此函数执行发送。由函数skb_is_tcp_pure_ack可知,实际上内核将纯ACK报文的truesize设置为了2,相应套接口的sk_wmem_alloc在发送纯ACK报文时增加了2。特别要注意的是SKB的销毁回调函数,如果是纯ACK报文,其为__sock_wfree,反之,非纯ACK报文,使用tcp_wfree。
static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, gfp_t gfp_mask)
{
skb->destructor = skb_is_tcp_pure_ack(skb) ? __sock_wfree : tcp_wfree;
skb_set_hash_from_sk(skb, sk);
refcount_add(skb->truesize, &sk->sk_wmem_alloc);
}
static inline bool skb_is_tcp_pure_ack(const struct sk_buff *skb)
{
return skb->truesize == 2;
}
四、发送完成中断
当数据发送完成中断发生时,将调用destructor回调销毁SKB,调用如下的tcp_wfree函数,但是由于此时很可能获得了Qdisc锁,不能直接在此函数中发送之前autocork住的数据。内核调度TSQ的tasklet执行实际的发送。详情见TSQ的介绍:https://blog.csdn.net/sinat_20184565/article/details/89341370。由于纯ACK的销毁回调函数为__sock_wfree,所以在tcp_should_autocork判断函数中,如果Qdisc或者NIC队列中的报文为纯ACK报文,不能使能autocork。
void tcp_wfree(struct sk_buff *skb)
{
WARN_ON(refcount_sub_and_test(skb->truesize - 1, &sk->sk_wmem_alloc));
for (oval = READ_ONCE(sk->sk_tsq_flags);; oval = nval) {
if (!(oval & TSQF_THROTTLED) || (oval & TSQF_QUEUED))
goto out;
nval = (oval & ~TSQF_THROTTLED) | TSQF_QUEUED | TCPF_TSQ_DEFERRED;
nval = cmpxchg(&sk->sk_tsq_flags, oval, nval);
if (nval != oval)
continue;
local_irq_save(flags);
tsq = this_cpu_ptr(&tsq_tasklet);
empty = list_empty(&tsq->head);
list_add(&tp->tsq_node, &tsq->head);
if (empty)
tasklet_schedule(&tsq->tasklet);
local_irq_restore(flags);
return;
}
}
边栏推荐
猜你喜欢
中国人保为德科康材承保产品责任险,为消费者权益保驾护航!
小程序导航及导航传参
How does a new tester do functional testing?Test thinking is really important
It's almost 35, still "did a little"?What happened to the test workers who had been in the industry for a few years?
程序国际化
zabbix添加监控主机和自定义监控项
三极管开关电路参数设计与参数介绍
从零开始配置 vim(9)——初始配置
Embedded Sharing Collection 32
Take you to an in-depth understanding of the version update of 3.4.2, what does it bring to users?
随机推荐
shell文本编辑awk
Did not detect default resource location for test class xxxx
flutter 创建可增型列表和列表排序
goland console shows overlapping problem solution
使用 requestAnimationFrame 提升 web 性能
leetcode-218.天际线问题
BFF避坑指南
如何使用腾讯字体,已经在什么场合下可以使用该字体?TTTGB-Medium
c语言进阶篇:动态内存管理(相关函数、常见错误、笔试题)
三极管开关电路参数设计与参数介绍
js阻止事件冒泡方案
ARP Spoofing - Tutorial Details
js原型和原型链以及原型继承
清洁环保的小型风电滑环基本介绍
Flink学习15:Flink自定义数据源
(面试加分新技能) 总结11个ES2022中你可能遗漏的语法
10个超赞的C语言开源项目,值得学习
电子产品结构设计中的电磁兼容性(EMC)设计
【Verilog数字系统设计(夏雨闻)5-------模块的结构、数据类型、变量和基本运算符号1】
小程序分包及分包预下载