跳至正文

TCP拥塞控制算法的实现

  • 技术

基于对google提出的bbr算法源码阅读的一些学习:

https://github.com/torvalds/linux/blob/master/net/ipv4/tcp_bbr.c#L39

并不详细介绍bbr的原理,也不逐行解释

拥塞接口

TCP底层的拥塞控制通过若干个定义在TCP层的接口被模块化了,不同的算法就可以直接hook对应需要的回调来实现不同的TCP拥塞控制算法。

Linux内核机制

  • 内核模块化,通过module_init和module_exit来初始化和卸载一个模块。
  • 模块开发不能使用常规的库函数,例如printf, malloc,需要使用内核提供的:printk, kmalloc。
  • 模块是系统的一部分,所以模块卸载需要自己卸载干净,系统不会帮忙进行回收。
  • 模块内开发不能直接对用户指针的对象取值或者复制,因为那是用户空间的地址,在内核空间会没有映射导致有问题,需要使用put_user给用户空间的内存地址复制。
  • 与上类似的函数还有:copy_to_user,copy_from_user,get_user,put_user。
  • 拥塞控制的结构体是:tcp_congestion_ops,定义了一系列的事件函数,通过hook这些函数实现不同的TCP拥塞控制算法。
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,                   // 在拥塞状态下,发包前的回调,用于更新拥塞窗口和传输速度
    .sndbuf_expand  = bbr_sndbuf_expand,        // 返回给tcp_sndbuf_expand使用的乘数
    .undo_cwnd  = bbr_undo_cwnd,                // 损失后cwnd的新值
    .cwnd_event = bbr_cwnd_event,               // 当发生拥塞时的回调
    .ssthresh   = bbr_ssthresh,                   // 返回慢启动的阈值
    .min_tso_segs   = bbr_min_tso_segs,           // 系统sysctl_tcp_min_tso_segs的重写
    .get_info   = bbr_get_info,                   // 获取inet的日志信息
    .set_state  = bbr_set_state,                // ca_state变化前会调用
};

static int __init bbr_register(void)
{
    BUILD_BUG_ON(sizeof(struct bbr) > ICSK_CA_PRIV_SIZE);
    return tcp_register_congestion_control(&tcp_bbr_cong_ops);
}

static void __exit bbr_unregister(void)
{
    tcp_unregister_congestion_control(&tcp_bbr_cong_ops);
}

module_init(bbr_register);
module_exit(bbr_unregister);
  • BUILD_BUG_ON是编译时的检测,为了保证bbr的结构体小于等于内核准备的空间大小。
  • 不同的机器的ICSK_CA_PRIV_SIZE值可能不同,但是编译确定下来还有bbr的空间大小和分布,所以一个系统编译,其他系统也是能够使用的。
  • do_div表示除法函数mod = do_div(x, y),结果存储在x中,余数存储在mod中。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

目录