当前位置:网站首页>TCP协议之《TSQ限值tcp_limit_output_bytes》
TCP协议之《TSQ限值tcp_limit_output_bytes》
2022-08-10 03:26:00 【程序员扫地僧】
TCP在发送大量的数据时,倾向于尽可能多的进行发送直到检测到丢包。这将导致发送设备或者Qdisc流控队列(例如pfifo_fast)中填充大量数据包,势必增大其它流量的延迟时间。tcp_limit_output_bytes参数限制了Qdisc队列或者设备队列中的数据量,以缓解此状况,达到减低队列的内存膨胀bufferbloat和由其所导致的异常RTT时间的作用。
默认值为262144。参见PROC文件tcp_limit_output_bytes的值,以及在初始化函数tcp_sk_init中的赋值。
$ cat /proc/sys/net/ipv4/tcp_limit_output_bytes
262144
$
static struct ctl_table ipv4_net_table[] = {
{
.procname = "tcp_limit_output_bytes",
.data = &init_net.ipv4.sysctl_tcp_limit_output_bytes,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec
},
}
static int __net_init tcp_sk_init(struct net *net)
{
/* Default TSQ limit of four TSO segments */
net->ipv4.sysctl_tcp_limit_output_bytes = 262144;
}
当前发送的数据报文skb结构所占用空间的两倍(2*skb->truesize),以及当前大约每毫秒的流量值,其通过sk_pacing_rate计算而来,内核将sk_pacing_shift变量定义为10,将当前每秒钟的流量(sk_pacing_rate)除以2的10次方,得到大约1毫秒的流量值。取两者之间的较大值,但是如果此值大约tcp_limit_output_bytes限定的值,使用tcp_limit_output_bytes作为判定值。之后,如果是重传报文,即factor等于1,将最终的判定值增大一倍。
如果sk_wmem_alloc大于limit说明以及发送了太多的数据在Qdisc或者设备队列,但是如果重传队列为空,此次发送还是允许进行。否则,返回true,禁止发送操作。
static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, unsigned int factor)
{
unsigned int limit;
limit = max(2 * skb->truesize, sk->sk_pacing_rate >> sk->sk_pacing_shift);
limit = min_t(u32, limit, sock_net(sk)->ipv4.sysctl_tcp_limit_output_bytes);
limit <<= factor;
if (refcount_read(&sk->sk_wmem_alloc) > limit) {
/* Always send skb if rtx queue is empty. No need to wait for TX completion to call us back,
* after softirq/tasklet schedule. This helps when TX completions are delayed too much.
*/
if (tcp_rtx_queue_empty(sk))
return false;
set_bit(TSQ_THROTTLED, &sk->sk_tsq_flags);
/* It is possible TX completion already happened before we set TSQ_THROTTLED, so we must test again the condition. */
smp_mb__after_atomic();
if (refcount_read(&sk->sk_wmem_alloc) > limit)
return true;
}
return false;
}
void sock_init_data(struct socket *sock, struct sock *sk)
{
sk->sk_max_pacing_rate = ~0U;
sk->sk_pacing_rate = ~0U;
sk->sk_pacing_shift = 10;
}
在TCP发送函数tcp_write_xmit和重传函数tcp_xmit_retransmit_queue中,调用检查队列大小的函数tcp_small_queue_check。发送函数传入的第三个factor参数为0,重传函数的factor传入1,即重传时设备或者Qdisc队列容量增大一倍。
static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, int push_one, gfp_t gfp)
{
while ((skb = tcp_send_head(sk))) {
if (tcp_small_queue_check(sk, skb, 0))
break;
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
break;
}
void tcp_xmit_retransmit_queue(struct sock *sk)
{
if (tcp_small_queue_check(sk, skb, 1))
return;
if (tcp_retransmit_skb(sk, skb, segs))
return;
}
边栏推荐
猜你喜欢
随机推荐
goland控制台显示重叠问题解决方案
day17正则表达式作业
使用注解实现限流
全面深入了解什么是反向代理和负载均衡
socket编程基础
带你深入理解3.4.2的版本更新,对用户带来了什么?
什么是Jmeter?Jmeter使用的原理步骤是什么?
It's almost 35, still "did a little"?What happened to the test workers who had been in the industry for a few years?
Small program subcontracting and subcontracting pre-download
动态网页开发基础
过水滑环的结构和工作原理
Classes and interfaces
shell文本编辑awk
js阻止事件冒泡方案
vue项目 npm run build 打包项目防止浏览器缓存
线程和线程间通信(C语言)
书法家唐效奇
微信小程序相互跳转如何携带参数
maya图片如何导入
How does a new tester do functional testing?Test thinking is really important