系统相关
首页 > 系统相关> > Linux网络新技术基石:eBPF and XDP

Linux网络新技术基石:eBPF and XDP

作者:互联网

hi,大家好,欢迎来到极客重生的世界,今天给大家分享的是Linux 网络新技术,当前正流行网络技是什么?那就是eBPF和XDP技术,Cilium+eBPF超级火热,Google GCP也刚刚全面转过来。

新技术出现的历史原因

廉颇老矣,尚能饭否

iptables/netfilter

iptables/netfilter 是上个时代Linux网络提供的优秀的防火墙技术,扩展性强,能够满足当时大部分网络应用需求,如果不知道iptables/netfilter是什么,请参考之前文章:一个奇葩的网络问题,把技术砖家"搞蒙了" ,里面对iptables/netfilter技术有详细介绍。

但该框架也存在很多明显问题:

netfilter 框架在IP层,报文需要经过链路层,IP层才能被处理,如果是需要丢弃报文,会白白浪费很多CPU资源,影响整体性能;

图片

如上图所示,极端情况下,报文需要依次遍历所有规则,才能匹配中,极大影响报文处理性能;

netfilter 框架类似一套可以自由添加策略规则专家系统,并没有对添加规则进行合并优化,这些都严重依赖操作人员技术水平,随着规模的增大,规则数量n成指数级增长,而报文处理又是0(n)复杂度,最终性能会直线下降。

内核协议栈

图片

随着互联网流量越来愈大, 网卡性能越来越强,Linux内核协议栈在10Mbps/100Mbps网卡的慢速时代是没有任何问题的,那个时候应用程序大部分时间在等网卡送上来数据。

现在到了1000Mbps/10Gbps/40Gbps网卡的时代,数据被很快地收入,协议栈复杂处理逻辑,效率捉襟见肘,把大量报文堵在内核里。

各类链表在多CPU环境下的同步开销。

不可睡眠的软中断路径过长。

sk_buff的分配和释放。

内存拷贝的开销。

上下文切换造成的cache miss。

于是,内核协议栈各种优化措施应着需求而来:

网卡RSS,多队列。

中断线程化。

分割锁粒度。

Busypoll。

但却都是见招拆招,治标不治本。问题的根源不是这些机制需要优化,而是这些机制需要推倒重构。蒸汽机车刚出来的时候,马车夫为了保持竞争优势,不是去换一匹昂贵的快马,而是卖掉马去买一台蒸汽机装上。基本就是这个意思。

重构的思路很显然有两个:

upload方法别让应用程序等内核了,让应用程序自己去网卡直接拉数据。

offload方法别让内核处理网络逻辑了,让网卡自己处理。

总之,绕过内核就对了,内核协议栈背负太多历史包袱。

DPDK让用户态程序直接处理网络流,bypass掉内核,使用独立的CPU专门干这个事。

XDP让灌入网卡的eBPF程序直接处理网络流,bypass掉内核,使用网卡NPU专门干这个事

如此一来,内核协议栈就不再参与数据平面的事了,留下来专门处理诸如路由协议,远程登录等控制平面和管理平面的数据流。


改善iptables/netfilter的规模瓶颈,提高Linux内核协议栈IO性能,内核需要提供新解决方案,那就是eBPF/XDP框架,让我们来看一看,这套框架是如何解决问题的。

eBPF到底是什么?

eBPF的历史

BPF 是 Linux 内核中高度灵活和高效的类似虚拟机的技术,允许以安全的方式在各个挂钩点执行字节码。它用于许多 Linux 内核子系统,最突出的是网络、跟踪和安全(例如沙箱)。

图片

BPF架构

BPF 是一个通用目的 RISC 指令集,其最初的设计目标是:用 C 语言的一个子集编 写程序,然后用一个编译器后端(例如 LLVM)将其编译成 BPF 指令,稍后内核再通 过一个位于内核中的(in-kernel)即时编译器(JIT Compiler)将 BPF 指令映射成处理器的原生指令(opcode ),以取得在内核中的最佳执行性能。

图片

BPF指令

尽管 BPF 自 1992 年就存在,扩展的 Berkeley Packet Filter (eBPF) 版本首次出现在 Kernel3.18中,如今被称为“经典”BPF (cBPF) 的版本已过时。许多人都知道 cBPF是tcpdump使用的数据包过滤语言。现在Linux内核只运行 eBPF,并且加载的 cBPF 字节码在程序执行之前被透明地转换为内核中的eBPF表示。除非指出 eBPF 和 cBPF 之间的明确区别,一般现在说的BPF就是指eBPF。

eBPF总体设计

图片

    

eBPF总体设计包括以下几个部分:

eBPF Runtime

图片

eBPF Hooks

图片

eBPF Maps

图片

Map 类型

- Hash tables, Arrays

- LRU (Least Recently Used)

- Ring Buffer

- Stack Trace

- LPM (Longest Prefix match)

作用

eBPF Helpers

图片

有哪些Helpers?

eBPF Tail and Function Calls

图片

尾调用有什么用?

● 将程序链接在一起

● 将程序拆分为独立的逻辑组件

● 使 BPF 程序可组合

函数调用有什么用?

● 重用内部的功能程序

● 减少程序大小(避免内联)

eBPF JIT Compiler

图片

eBPF可以做什么?

图片

eBPF 开源 Projects

图片

Cilium

图片

 

图片

Cilium在它的 datapath 中重度使用了 BPF 技术

图片

对比传统容器网络(采用iptables/netfilter):

图片

BCC(BPF Compiler Collection)

BCC 是一个框架,它使用户能够编写嵌入其中的 eBPF 程序的 Python 程序。该框架主要针对涉及应用程序和系统分析/跟踪的用例,其中 eBPF 程序用于收集统计信息或生成事件,用户空间中的对应部分收集数据并以人类可读的形式显示。运行 python 程序将生成 eBPF 字节码并将其加载到内核中。

图片

bpftrace

bpftrace 是一种用于 Linux eBPF 的高级跟踪语言,可在最近的 Linux 内核 (4.x) 中使用。bpftrace 使用 LLVM 作为后端将脚本编译为 eBPF 字节码,并利用 BCC 与 Linux eBPF 子系统以及现有的 Linux 跟踪功能进行交互:内核动态跟踪 (kprobes)、用户级动态跟踪 (uprobes) 和跟踪点. bpftrace 语言的灵感来自 awk、C 和前身跟踪器,例如 DTrace 和 SystemTap。

图片

eBPF Go 库

eBPF Go 库提供了一个通用的 eBPF 库,它将获取 eBPF 字节码的过程与 eBPF 程序的加载和管理解耦。eBPF 程序通常是通过编写高级语言创建的,然后使用 clang/LLVM 编译器编译为 eBPF 字节码。

图片

libbpf C/C++ 库

libbpf 库是一个基于 C/C++ 的通用 eBPF 库,它有助于解耦从 clang/LLVM 编译器生成的 eBPF 目标文件加载到内核中,并通过提供易于使用的库 API 来抽象与 BPF 系统调用的交互应用程序。

图片

那XDP又是什么?

XDP的全称是: eXpress Data Path

XDP 是Linux 内核中提供高性能、可编程的网络数据包处理框架。

XDP整体框架

图片

XDP总体设计

图片

XDP总体设计包括以下几个部分:

XDP驱动

网卡驱动中XDP程序的一个挂载点,每当网卡接收到一个数据包就会执行这个XDP程序;XDP程序可以对数据包进行逐层解析、按规则进行过滤,或者对数据包进行封装或者解封装,修改字段对数据包进行转发等;

BPF虚拟机

并没有在图里画出来,一个XDP程序首先是由用户编写用受限制的C语言编写的,然后通过clang前端编译生成BPF字节码,字节码加载到内核之后运行在eBPF虚拟机上,虚拟机通过即时编译将XDP字节码编译成底层二进制指令;eBPF虚拟机支持XDP程序的动态加载和卸载;

BPF maps

存储键值对,作为用户态程序和内核态XDP程序、内核态XDP程序之间的通信媒介,类似于进程间通信的共享内存访问;用户态程序可以在BPF映射中预定义规则,XDP程序匹配映射中的规则对数据包进行过滤等;XDP程序将数据包统计信息存入BPF映射,用户态程序可访问BPF映射获取数据包统计信息;

BPF程序校验器

XDP程序肯定是我们自己编写的,那么如何确保XDP程序加载到内核之后不会导致内核崩溃或者带来其他的安全问题呢?程序校验器就是在将XDP字节码加载到内核之前对字节码进行安全检查,比如判断是否有循环,程序长度是否超过限制,程序内存访问是否越界,程序是否包含不可达的指令;

XDP Action

XDP用于报文的处理,支持如下action:

enum xdp_action {    XDP_ABORTED = 0,    XDP_DROP,    XDP_PASS,    XDP_TX,    XDP_REDIRECT,};


AF_XDP

AF_XDP 是为高性能数据包处理而优化的地址族,AF_XDP 套接字使 XDP 程序可以将帧重定向到用户空间应用程序中的内存缓冲区。

XDP设计原则

XDP技术优势

及时处理

高性能优化

指令虚拟机

可扩展模型

可编程性

XDP 工作模式

XDP 有三种工作模式,默认是 native(原生)模式,当讨论 XDP 时通常隐含的都是指这 种模式。

XDP vs DPDK

图片

相对于DPDK,XDP:

优点

缺点

注意XDP的性能提升是有代价的,它牺牲了通用型和公平性

如何选择?

XDP适合场景

XDP例子

下面是一个最小的完整 XDP 程序,实现丢弃包的功能(xdp-example.c):

#include <linux/bpf.h>

#ifndef __section
# define __section(NAME)                  \
   __attribute__((section(NAME), used))
#endif

__section("prog")
int xdp_drop(struct xdp_md *ctx)
{
    return XDP_DROP;
}

char __license[] __section("license") = "GPL";

用下面的命令编译并加载到内核:

$ clang -O2 -Wall -target bpf -c xdp-example.c -o xdp-example.o
$ ip link set dev em1 xdp obj xdp-example.o

以上命令将一个 XDP 程序 attach 到一个网络设备,需要是 Linux 4.11 内核中支持 XDP 的设备,或者 4.12+ 版本的内核。

最后

eBPF/XDP 作为Linux网络革新技术正在悄悄改变着Linux网络发展模式。

eBPF正在将Linux内核转变为微内核,越来越多的新内核功能采用eBPF实现,让新增内核功能更加快捷高效。

总体而言,基于业界基准测试结果,eBPF 显然是解决具有挑战性的云原生需求的最佳技术。

参考&延伸阅读

The eXpress Data Path: 

Fast Programmable Packet Processing in the Operating System Kernel

https://docs.cilium.io/en/v1.6/bpf/

bpf-rethinkingthelinuxkernel-200303183208

https://ebpf.io/what-is-ebpf/

https://www.kernel.org/doc/html/latest/networking/af_xdp.html

https://cilium.io/blog/2021/05/11/cni-benchmark

https://blog.csdn.net/dog250/article/details/107243696

- END -

标签:BPF,XDP,程序,eBPF,内核,Linux
来源: https://blog.csdn.net/flynetcn/article/details/119487894