基于对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中。