当前位置:网站首页>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;
}
边栏推荐
- Arrays类
- 使用 requestAnimationFrame 提升 web 性能
- Neo4J 与 Cypher 查询语言基础
- Take you to an in-depth understanding of the version update of 3.4.2, what does it bring to users?
- uni-app自定义导航栏
- golang中的URL 的编码和解码(转)
- Jackson的ObjectMapper在项目中的主要运用
- flutter 创建可增型列表和列表排序
- 驱动程序开发:无设备树和有设备树的platform驱动
- 【Verilog数字系统设计(夏雨闻)6-------模块的结构、数据类型、变量和基本运算符号2】
猜你喜欢
随机推荐
Arrays类
program internationalization
二维空间下的向量旋转
js阻止事件冒泡方案
golang中的URL 的编码和解码(转)
YAPI使用
leetcode 27:移除元素
Shell 文本三剑客 awk
exchange2010 邮件数据库无法装入
applet wxs
flutter 制作嵌套列表
清洁环保的小型风电滑环基本介绍
数据库设计中反映用户对数据要求的模式叫什么
小程序导航及导航传参
从零开始配置 vim(9)——初始配置
改版后的CSDN如何更换皮肤
Software life cycle (the work of each phase of software engineering)
学习总结week4_1json
mediaserver创建
RoyalScope分析仪:CAN总线波形台阶和信号幅值低的问题