菜鸟笔记
提升您的技术认知

ebpf技术实践:高性能acl-ag真人游戏

对于 linux 而言,iptables / nftables 是主流的网络 acl(access control list)ag真人游戏的解决方案。近些年随着 ebpf 技术的快速发展,bpfilter 也被提上了日程,有望取代 iptables/nftables,成为下一代网络 acl 的ag真人游戏的解决方案。

本文追随 bpfilter 的脚步,利用 xdp ebpf 技术解决 iptables / nftables 性能瓶颈,提供一种高性能网络 acl 的技术ag真人游戏的解决方案。

由于 iptables 和 nftables 的技术相似,但 iptables 相较简单,所以我们用 iptables 举例分析:

o(n)匹配

iptables 的规则样式:

# iptables -a input -m set --set black_list src -j drop
# ......省略n条规则
# iptables -a input -p tcp -m multiport --dports 53,80 -j accept
# ......省略n条规则
# iptables -a input -p udp --dport 53 -j accept

如上所示,若匹配 dns 的请求报文(目的端口 53 的 udp 报文),需要依次遍历所有规则,才能匹配中。其中,ipset/multiport 等 match 项,只能减少规则数量,无法改变 o(n)的匹配方式。

协议栈丢包

iptables 常常和 ipset 结合使用,设置一些 ip 地址黑名单,防御 ddos(distributed denial-of-service)网络攻击。对于 ddos 这样的网络攻击,更早地丢包,就能更好地缓解 cpu 的损耗。但是用 iptables 作为防 ddos 攻击的手段,效果往往很差。是因为 iptables 基于 netfilter 框架实现,即便是攻击报文在 netfilter 框架 prerouting 的 hook 点(收包路径的最早 hook 点)丢弃,也已经走过了很多 linux 网络协议栈的处理流程。网上有比较数据,利用 xdp 技术的丢包速率要比 iptables 高 4 倍左右:

  • 预置条件:单条 udp 流、单个 cpu 处理

  • cpu: i7-6700k cpu @ 4.00ghz

  • nic: 50gbit/s mellanox-cx4

  • iptables 规则:iptables -t raw -i prerouting -m set --set black_list src -j drop

  • iptables 丢包速率:4,748,646 pps

  • xdp:percpu_hash 类型的 ebpf map,存储 ip 黑名单

  • xdp 丢包速率:16,939,941 pps

xdp(express data path)是基于 ebpf 实现的高性能、可编程的数据平面技术。基本的软件架构如下图所示:

xdp 位于网卡驱动层,当数据包经过 dma 存放到 ring buffer 之后,分配 skb 之前,即可被 xdp 处理。数据包经过 xdp 之后,会有 4 种去向:

  • xdp_drop:丢包

  • xdp_pass:上送协议栈

  • xdp_tx:从当前网卡发送出去

  • xdp_redirect:从其他网卡发送出去

    由于 xdp 位于整个 linux 内核网络软件栈的底部,能够非常早地识别并丢弃攻击报文,具有很高的性能。这为我们改善 iptables/nftables 协议栈丢包的性能瓶颈,提供了非常棒的ag真人游戏的解决方案。

bpf(berkeley packet filter)是 linux 内核提供的基于 bpf 字节码的动态注入技术(常应用于 tcpdump、raw socket 过滤等)。ebpf(extended berkeley packet filter)是针对于 bpf 的扩展增强,丰富了 bpf 指令集,提供了 map 的 kv 存储结构。我们可以利用 bpf()系统调用,初始化 ebpf 的 program 和 map,利用 netlink 消息或者 setsockopt()系统调用,将 ebpf 字节码注入到特定的内核处理流程中(如 xdp、socket filter 等)。如下图所示:

至此,我们高性能 acl 的技术方向已经明确,即利用 xdp 技术在软件栈的最底层做报文的过滤。

如下图所示,acl 控制平面负责创建 ebpf 的 program、map,注入 xdp 处理流程中。其中 ebpf 的 program 存放报文匹配、丢包等处理逻辑,ebpf 的 map 存放 acl 规则。

为了提升匹配效率,我们将所有的 acl 规则做了预处理,将链式的规则拆分存储。规则匹配时,我们参考内核的 o(1)调度算法,在多个匹配的规则中,快速选取高优先级的规则。

规则预处理

我们以之前的 iptables 规则举例,看如何将其拆分存储。首先,将所有规则根据优先级编号。比如,例子中的规则分别编号为:1(0x1)、16(0x10)、256(0x100)。其次,将所有规则的匹配项归类拆分。比如,例子中的匹配项可以归类为:源地址、目的端口、协议。最后,将规则编号、具体匹配项分类存储到 ebpf 的 map 中。

# ipset create black_list hash:net
# ipset add black_list 192.168.3.0/24
# iptables -a input -m set --set black_list src -j drop
# ...... 省略15条规则
# iptables -a input -p tcp -m multiport --dports 53,80 -j accept
# ...... 省略240条规则
# iptables -a input -p udp --dport 53 -j accept

举例说明:

规则 1 只有源地址匹配项,我们用源地址 192.168.3.0/24 作为 key,规则编号 0x1 作为 value,存储到 src map 中。

规则 16 有目的端口、协议 2 个匹配项,我们依次将 53、80 作为 key,规则编号 0x10 作为 value,存储到 dport map 中;将 tcp 协议号 6 作为 key,规则编号 0x10 作为 value,存储到 proto map 中。

规则 256 有目的端口、协议 2 个匹配项,我们将 53 作为 key,规则编号 0x100 作为 value,存储到 sport map 中;将 udp 协议号 17 作为 key,规则编号 0x100 作为 value,存储到 proto map 中。

我们依次将规则 1、16、256 的规则编号作为 key,动作作为 value,存储到 action map 中。

交集

需要注意的是,规则 16、256 均有目的端口为 53 的匹配项,我们应该将 16、256 的规则编号进行按位或操作,然后进行存储,即 0x10 | 0x100 = 0x110。

通配

另外,规则 1 的目的端口、协议均为通配项,我们应该将规则 1 的编号按位或追加到现有的匹配项中(图中下划线的 value 值:0x111、0x11 等)。同理,将规则 16、256 的规则编号按位或追加到现有的源地址匹配项中(图中下划线的 value 值:0x111、0x110)。至此,我们的规则预处理完成,将所有规则的匹配项、动作拆分存储到 6 个 ebpf map 中,如上图所示。

类 o(1)匹配

报文匹配时,我们报文的 5 元组(源、目的地址,源、目的端口、协议)依次作为 key,分别查找对应的 ebpf map,得到 5 个 value。我们将这 5 个 value 进行按位与操作,得到一个 bitmap。这个 bitmap 的每个 bit,就表示了对应的一条规则;被置位为 1 的 bit,表示对应的规则匹配成功。

举例说明:

当用报文(192.168.4.1:10000 -> 192.168.4.100:53, udp)的 5 元组作为 key,查找 ebpf map 后,得到的 value 分别为:src_value = 0x110、dst_value = null、sport_value = null、dport_value = 0x111、proto_value = 0x101。将非 null 的 value 进行按位与操作,得到 bitmap = 0x100(0x110 & 0x111 & 0x101)。由于 bitmap 只有一位被置位 1(只有一条规则匹配成功,即规则 256),利用该 bitmap 作为 key,查找 action map,得到 value 为 accept。与 iptables 的规则匹配结果一致。

同理,当报文(192.168.4.1:1000 -> 192.168.4.100:53, tcp)的 5 元组作为 key,查找 ebpf map 后,处理的流程和上面的一致,最终匹配到规则 16。

同样,当报文(192.168.3.1:1000 -> 192.168.4.100:53, udp)的 5 元组作为 key,查找 ebpf map 后,处理的流程和上面的一致。不同的是,得到的 bitmap = 0x101,由于 bitmap 有两位被置位 1(规则 1、256),我们应该取优先级最高的规则编号作为 key,查找 action map。这里借鉴了内核 o(1)调度算法的思想,做如下操作:

bitmap &= -bitmap

即可取到优先级最高的 bit,如 0x101 &= -(0x101)最终等于 0x1。我们用 0x1 作为 key,查找 action map,得到 value 为 drop。与 iptables 的规则匹配结果一致。

本文基于 linux 内核的 xdp 机制,提出了一种改善 iptables / nftables 性能的 acl 方案。目前 ebpf 的技术在开源社区非常流行,特性非常丰富,我们可以利用这项技术做很多有意思的事情。

网站地图