博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个linux bbr存在的调用顺序bug
阅读量:6573 次
发布时间:2019-06-24

本文共 2862 字,大约阅读时间需要 9 分钟。

最近跟踪bbr的状态转换的代码,发现一个问题:

[11241.360364]mode=3,min_rtt_us=553,full_bw=0,cycle_idx=0,pacing_gain=0,cwnd_gain=0,rtt_cnt=0[11241.360373] main mode=3,min_rtt_us=553,cur_bw=0,cycle_idx=0,pacing_gain=256,cwnd_gain=256,rtt_cnt=0,snd_cwnd=4[11241.360377]mode=0,min_rtt_us=553,full_bw=0,cycle_idx=0,pacing_gain=256,cwnd_gain=256,rtt_cnt=0

可以看到,bbr的第一个处理,是mode=3,也就是执行链:

bbr_main-->bbr_update_model-->bbr_update_min_rtt-->
 
static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs){    struct tcp_sock *tp = tcp_sk(sk);    struct bbr *bbr = inet_csk_ca(sk);    bool filter_expired;    /* Track min RTT seen in the min_rtt_win_sec filter window: */    filter_expired = after(tcp_jiffies32,                   bbr->min_rtt_stamp + bbr_min_rtt_win_sec * HZ);    if (rs->rtt_us >= 0 &&        (rs->rtt_us <= bbr->min_rtt_us || filter_expired)) {        bbr->min_rtt_us = rs->rtt_us;        bbr->min_rtt_stamp = tcp_jiffies32;    }    if (bbr_probe_rtt_mode_ms > 0 && filter_expired &&        !bbr->idle_restart && bbr->mode != BBR_PROBE_RTT) {        bbr->mode = BBR_PROBE_RTT;  /* dip, drain queue */-----------------------第一个状态值

而按到正常的设计,一般来说,是先调用init再执行拥塞控制。按道理,filter_expired怎么会为1呢?因为链路刚建立,bbr->min_rtt_stamp  的初始化值是当前时间啊,还没有经过10s,

经过打点,发现bbr->min_rtt_stamp 是0,而不是bbr_init之后的值。然后继续分析代码:

static struct tcp_congestion_ops tcp_bbr_cong_ops __read_mostly = {    .flags        = TCP_CONG_NON_RESTRICTED,    .name        = "bbr",    .owner        = THIS_MODULE,    .init        = bbr_init,----------------------------初始化函数    .cong_control    = bbr_main,------------------------bbr拥塞控制的主函数    .sndbuf_expand    = bbr_sndbuf_expand,    .undo_cwnd    = bbr_undo_cwnd,    .cwnd_event    = bbr_cwnd_event,    .ssthresh    = bbr_ssthresh,    .tso_segs_goal    = bbr_tso_segs_goal,    .get_info    = bbr_get_info,    .set_state    = bbr_set_state,};

这样就导致了,init函数的调用在bbr_main函数之后,而不是之前。

根据tcp链接的建立调用链:

tcp_rcv_synsent_state_process-->tcp_finish_connect-->tcp_init_transfer-->tcp_init_congestion_control-->icsk->icsk_ca_ops->init(sk);
这个时候发起请求的客户端会调用拥塞控制函数的init,
tcp_rcv_synsent_state_process-->tcp_ack-->tcp_cong_control-->
static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked,                 int flag, const struct rate_sample *rs){    const struct inet_connection_sock *icsk = inet_csk(sk);    if (icsk->icsk_ca_ops->cong_control) {------------------------bbr走这个分支        icsk->icsk_ca_ops->cong_control(sk, rs);        return;    }

而在 tcp_rcv_synsent_state_process 函数中,

static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,                     const struct tcphdr *th){。。。。tcp_ack();。。。。smp_mb();tcp_finish_connect(sk, skb);。。。。}

所以可以看出,拥塞函数调用是在拥塞init调用之前。

从github上最新的内核2019-2-21号的版本来看,也存在这个问题,不知道是google故意为之还是bug,个人认为应该是bug,毕竟影响了一段时间的状态以及初始值。

有心的童鞋可以去提交一个patch解决。

 

转载于:https://www.cnblogs.com/10087622blog/p/10412440.html

你可能感兴趣的文章
CentOS搭建Git服务器
查看>>
多线程篇六:线程池
查看>>
easyui tab页面关闭根据回调函数刷新父tab页
查看>>
GPS围栏两个多边形相交问题的奇葩解法
查看>>
PHPstorm如何导入字体主题
查看>>
静态链表
查看>>
在VS中手工创建一个最简单的WPF程序
查看>>
python for 格式化字符串 list.count
查看>>
"网络适配器本地连接没有有效ip地址配置"错误的解决办法
查看>>
360随身WIFI作USB无线网卡的做法
查看>>
网站设计中很重要的概念div+浮动
查看>>
js平滑滚动到顶部,底部,指定地方 animate()
查看>>
OC-NSFileManager
查看>>
printf和sprintf
查看>>
数组分割
查看>>
O(1) O(n)
查看>>
iphone socket讲解
查看>>
CAS机制详解
查看>>
odoo开发笔记 -- 翻译机制及导入.po文件
查看>>
运维邮件
查看>>