0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何用eBPF写TCP拥塞控制算法?

Linux阅码场 来源:csdn 作者:dog250 2020-12-26 09:44 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

其实不想用这个题目的,只因为TCP相关的东西比较吸引人的眼球,这篇文章的主题还是eBPF,而不是TCP。

用eBPF写TCP拥塞控制算法只是本文所讲内容的一个再平凡不过的例子。

先看两个问题,或者说是两个痛点:

内核越来越策略化。

内核接口不稳定。

分别简单说一下。

所谓内核策略化就是说越来越多的灵巧的算法,小tricks等灵活多变的代码进入内核,举例来讲,包括但不限于以下这些:

TCP拥塞控制算法。

TC排队规则,数据包调度算法。

各种查找的哈希算法。

这部分策略化的代码几乎都是用“回调函数”实现的,这在另一方面烘托了Linux内核也是模块化设计的,且机制和策略分离,当需要一种新的算法时,只需要register一组新的回调函数即可。

然而,…

然而不够完美,因为上述第2点,“内核接口不稳定”!即每一个内核版本的数据结构以及API都是不兼容的。

这意味着什么?

这意味着,即便是高度封装好的算法模块代码,也需要为不同版本的Linux内核维护一套代码,当涉及内核模块由于版本问题不得不升级时,数据结构和api的适配工作往往是耗时且出力不讨好的。

但其实,很多算法根本就是与内核数据结构,内核api这些无关的。

两个内核版本,数据结构只是字段变化了位置,新增了字段,更新了字段名字,即便如此,不得不对算法模块进行重新编译…

如果能在模块载入内核的时候,对函数和数据结构字段进行重定位就好了!

我们的目标是,一次编写,多次运行。

又是Facebook走在了前面,来自Facebook的BPF CO-RE(Compile Once – Run Everywhere):
http://vger.kernel.org/bpfconf2019_talks/bpf-core.pdf
没错,eBPF,就是它!

我们看下其描述:

BPF CO-RE talk discussed issues that developers currently run into when developing, testing, deploying, and running BPF applications at scale, taking Facebook’s experience as an example. Today, most types of BPF programs access internal kernel structures, which necessitates the need to compile BPF program’s C code “on the fly” on every single production machine due to changing struct/union layouts and definitions inside kernel. This causes many problems and inconveniences, starting from the need to have kernel sources available everywhere and in sync with running kernel, which is a hassle to set up and maintain. Reliance on embedded LLVM/Clang for compilation means big application binary size, increased memory usage, and some rare, but impactful production issues due to increased resource usage due to compilation. With current approach testing BPF programs against multitude of production kernels is a stressful, time-consuming, and error-prone process. The goal of BPF CO-RE is to solve all of those issues and move BPF app development flow closer to typical experience, one would expect when developing applications: compile BPF code once and distribute it as a binary. Having a good way to validate that BPF application will run without issues on all active kernels is also a must.

The complexity hides in the need to adjust compiled BPF assembly code to every specific kernel in production, as memory layout of kernel data structures changes between kernel versions and even different kernel build configurations. BPF CO-RE solution relies on self-describing kernel providing BTF type information and layout (ability to produce it was recently committed upstream). With the help from Clang compiler emitting special relocations during BPF compilation and with libbpf as a dynamic loader, it’s possible to reconciliate correct field offsets just before loading BPF program into kernel. As BPF programs are often required to work without modification (i.e., re-compilation) on multiple kernel versions/configurations with incompatible internal changes, there is a way to specify conditional BPF logic based on actual kernel version and configuration, also using relocations emitted from Clang. Not having to rely on kernel headers significantly improves the testing story and makes it possible to have a good tooling support to do pre-validation before deploying to production.

There are still issues which will have to be worked around for now. There is currently no good way to extract #define macro from kernel, so this has to be dealt with by copy/pasting the necessary definitions manually. Code directly relying on size of structs/unions has to be avoided as well, as it isn’t relocatable in general case. While there are some raw ideas how to solve issues like that in the future, BPF CO-RE developers prioritize providing basic mechanisms to allow “Compile Once - Run Everywhere” approach and significantly improve testing and pre-validation experience through better tooling, enabled by BPF CO-RE. As existing applications are adapted to BPF CO-RE, there will be new learning and better understanding of additional facilities that need to be provided to provide best developer experience possible.

该机制可以:

用eBPF的一组字节码实现内核模块的一组回调函数。

对使用到的内核数据结构字段进行重定位,适配当前内核的对应偏移。

后果就是:

很多内核算法模块可以用eBPF来编写了。

Linux 5.6用TCP拥塞控制算法举了一例,我们看一下:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=09903869f69f

可以看到,这个eBPF程序是与内核版本无关的,你可以看到它的tcp_sock结构体的定义:

struct tcp_sock { struct inet_connection_sock inet_conn; __u32 rcv_nxt; __u32 snd_nxt; __u32 snd_una; __u8 ecn_flags; __u32 delivered; __u32 delivered_ce; __u32 snd_cwnd; __u32 snd_cwnd_cnt; __u32 snd_cwnd_clamp; __u32 snd_ssthresh; __u8 syn_data:1, /* SYN includes data */ syn_fastopen:1, /* SYN includes Fast Open option */ syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ syn_fastopen_ch:1, /* Active TFO re-enabling probe */ syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ save_syn:1, /* Save headers of SYN packet */ is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */ syn_smc:1; /* SYN includes SMC */ __u32 max_packets_out; __u32 lsndtime; __u32 prior_cwnd;} __attribute__((preserve_access_index));

这里注意到两点:

该结构体并非内核头文件里的对应结构体,它只包含了内核对应结构体里TCP CC算法用到的字段,它是内核对应同名结构体的子集。

preserve_access_index属性表示eBPF字节码在载入的时候,会对这个结构体里的字段进行重定向,满足当前内核版本的同名结构体字段的偏移。

我们在看下eBPF实现的TCP CC回调函数是个什么样子:

BPF_TCP_OPS_3(tcp_reno_cong_avoid, void, struct sock *, sk, __u32, ack, __u32, acked){ struct tcp_sock *tp = tcp_sk(sk); if (!tcp_is_cwnd_limited(sk)) return; /* In "safe" area, increase. */ if (tcp_in_slow_start(tp)) { acked = tcp_slow_start(tp, acked); if (!acked) return; } /* In dangerous area, increase slowly. */ tcp_cong_avoid_ai(tp, tp->snd_cwnd, acked);}... SEC(".struct_ops")struct tcp_congestion_ops dctcp = { .init = (void *)dctcp_init, .in_ack_event = (void *)dctcp_update_alpha, .cwnd_event = (void *)dctcp_cwnd_event, .ssthresh = (void *)dctcp_ssthresh, .cong_avoid = (void *)tcp_reno_cong_avoid, .undo_cwnd = (void *)dctcp_cwnd_undo, .set_state = (void *)dctcp_state, .flags = TCP_CONG_NEEDS_ECN, .name = "bpf_dctcp",};

没啥特殊的,几乎和内核模块的写法一样,唯一不同的是:

它和内核版本无关了。你用llvm/clang编译出来.o字节码将可以被载入到所有的内核。

它让人感觉这是在用户态编程

是的,这就是在用户态写的TCP CC算法,eBPF字节码的对应verifier会对你的代码进行校验,它不允许可以crash内核的eBPF代码载入,你的危险代码几乎无法通过verify。

如果你想搞明白这一切背后是怎么做到的,看两个文件就够了:

net/ipv4/bpf_tcp_ca.c

kernel/bpf/bpf_struct_ops.c

当然,经理不会知道这意味着什么。

浙江温州皮鞋湿,下雨进水不会胖。

原文标题:用eBPF写TCP拥塞控制算法

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    4

    文章

    1476

    浏览量

    43092
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1433

    浏览量

    83777

原文标题:用eBPF写TCP拥塞控制算法

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    TCP/IP(Socket)协议深度剖析

    TCP/IP协议作为互联网通信的基础架构,其核心机制Socket编程承载着全球数据交换的使命。本文将深入剖析这一协议的七层架构、三次握手与四次挥手的精妙设计、流量控制拥塞控制的动态平
    的头像 发表于 03-03 17:06 797次阅读

    PID控制算法

    PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设计与实现过程,对于一般的研发人员来讲,应该是足够应对一般研发问题了,而难能可贵的是,在我所
    发表于 01-23 08:18

    看透微突发:利用 INT 技术实现交换机队列级的实时拥塞告警

    星融元开发的 EasyRoCE-CMA 是基于 INT 技术的拥塞监控工具 。它利用纳秒级精度的 HDC 与 BDC 捕获信息 ,实现交换机端口级拥塞与丢包的一站式可视化 。该工具能精准定位故障根因,辅助 AI 智算网络快速调优 。
    的头像 发表于 01-16 15:29 1402次阅读
    看透微突发:利用 INT 技术实现交换机队列级的实时<b class='flag-5'>拥塞</b>告警

    何用FPGA控制ADV7513实现HDMI画面显示和音频播放

    HDMI接口显示使用DMT时序+TMDS编码来实现。当用FPGA控制HDMI的数据传输时,通常可以采用纯RTL实现TMDS算法或者使用专门的HDMI芯片(如ADV7513)这两种方案来完成。本文主要是介绍如何用FPGA
    的头像 发表于 12-02 11:05 7051次阅读
    如<b class='flag-5'>何用</b>FPGA<b class='flag-5'>控制</b>ADV7513实现HDMI画面显示和音频播放

    ECN如何在HPC和数据中心中应对网络拥塞

    ECN(Explicit Congestion Notification)是一种改进后的拥塞控制方法,它不依赖于丢包来指示拥塞,而是在数据包的头部标记拥塞发生的信号。ECN通过向数据包
    的头像 发表于 09-26 14:53 2915次阅读
    ECN如何在HPC和数据中心中应对网络<b class='flag-5'>拥塞</b>

    解析DCQCN:RDMA在数据中心网络的关键拥塞控制协议

    DCQCN ( Data Center Quantized Congestion Notification),数据中心量化拥塞通知。它是一种专门为数据中心网络设计的端到端拥塞控制协议。其核心目的是在使用RDMA(RoCEv2)
    的头像 发表于 09-15 11:45 2094次阅读
    解析DCQCN:RDMA在数据中心网络的关键<b class='flag-5'>拥塞</b><b class='flag-5'>控制</b>协议

    PID控制算法学习笔记资料

    用于新手学习PID控制算法
    发表于 08-12 16:22 7次下载

    Modbus TCP 转 Modbus RTU电脑端 TCP 与西门子 V20 变频器的通信案例

    在工业自动化控制系统中,经常需要实现不同设备之间的通信与数据交互。本案例旨在展示如何通过 Modbus 协议,将电脑作为主站(Modbus TCP)与多台西门子变频器 V20(Modbus RTU
    的头像 发表于 07-27 17:19 1112次阅读
    Modbus <b class='flag-5'>TCP</b> 转 Modbus RTU电脑端 <b class='flag-5'>TCP</b> 与西门子 V20 变频器的通信案例

    基于eBPF的Kubernetes网络异常检测系统

    作为一名在云原生领域深耕多年的运维工程师,我见过太多因为网络问题导致的生产事故。传统的监控手段往往是事后诸葛亮,当你发现问题时,用户已经在抱怨了。今天,我将分享如何利用 eBPF 这一革命性技术,构建一套能够实时检测 Kubernetes 网络异常的系统。
    的头像 发表于 07-24 14:09 932次阅读

    什么是Modbus TCP协议

    Modbus TCP是一种基于TCP/IP协议的Modbus通信协议,用于在客户机和服务器之间进行数据通信。它常用于工业自动化控制、电力监控与管理、温湿度监测等领域。Modbus TCP
    的头像 发表于 07-23 17:18 4808次阅读
    什么是Modbus <b class='flag-5'>TCP</b>协议

    何用AI负载为SONiC交换机调整ECN水线

    显式拥塞通知(ECN)是计算机网络中的一种机制,它允许发送设备明确地通知接收设备网络拥塞,而不是依赖于传统的“丢包”方法。在传统的TCP/IP网络中,当路由器或交换机出现拥塞时,它会丢
    的头像 发表于 07-11 14:12 2773次阅读
    如<b class='flag-5'>何用</b>AI负载为SONiC交换机调整ECN水线

    当CCLinkIE撞上Modbus TCP:照明控制系统的“方言战争”终结术

    在楼宇自动化系统中,新旧协议的兼容性问题常成为工程师的“隐形绊脚石”。CCLinkIE网络的高速实时性与Modbus TCP照明控制器的通用性看似“天生对立”,但通过协议转换方案,两者可以实现“精准
    发表于 07-10 15:49

    CAN转Modbus TCP网关!CT机伺服控制精准扫描的“幕后功臣”

    在医疗器械CT机中,实现伺服电机的精密运动控制是保障设备精准扫描的关键。将JH-CAN-TCP疆鸿智能CAN主站转Modbus TCP作为从站连接西门子PLC,并利用CAN主站连接伺服电机,这一过程中网关发挥着不可或缺的作用。
    的头像 发表于 07-05 11:01 1001次阅读
    CAN转Modbus <b class='flag-5'>TCP</b>网关!CT机伺服<b class='flag-5'>控制</b>精准扫描的“幕后功臣”

    CAN转Modbus TCP网关赋能食品搅拌机智能协同控制

    在食品搅拌机的自动化控制系统中,设备通信协议的多样性给系统集成带来挑战。JH-CAN-TCP疆鸿智能CAN主站转Modbus TCP从站的网关,成为连接西门子PLC与伺服系统的关键桥梁。 西门子
    的头像 发表于 07-02 20:09 474次阅读

    RDMA简介7之可靠传输

    网络无损,需要进行严格的流量控制拥塞管理。流量控制指通过调整发送端的发送速率,确保接收端能够处理并接收所有数据包。RoCE v2使用了IEEE 802.11Qbb中提出的基于优先级的流量控制
    发表于 06-13 10:01