XDP EBPF防火墙

2021-04-26 10:51:59

今天可用的选项之一是在刻度下进行分毫秒的数据包过滤是为了利用各种NIC制造商提供的XDP,EBPF,Linux内核和支持的设施。

两个(XDP和EBPF)在Linux内核的5.x发布中迅速增长,绝对没有理由不希望将其用于低延迟,高性能用例。

在这篇文章中,我将演示一个示例XDP代码,它传统上由NetFilter / Iptables完成的IP层防火墙函数(谢谢您对所有鱼生锈的Russell!),但在Thelinux内核中的EBPF VM作为卸载的XDP程序。步行通过QEMU / Virtio的LLVM版本11.0.0彻底测试了Ubuntu 20.10。 LLVM是必填节,因为它可以产生EBPF目标。

根据XDP开发人员,在他们进行的基准测试中,XDP远离所有前端的传统内核网络堆栈onlinux - TX,RX和向前(按12-25倍的顺序),与NIC一起卸载XDPSUCH时来自英特尔/ Mellanox / Netronome(MLX / IXGBE / NFP等)的那些。

我们展示XDP每秒实现单核包处理的单核包处理,每秒高达2400万个数据包,并通过三个empluseUSE案例揭示编程模型的灵活性:第3层路由,内联DDOS保护和第4层LoadBaligancing

$ sudo apt-get install \ build-assigent \ libelf-dev \ ca-certificates \ ca-certificates-java \ zlib1g-dev \ llvm-11-dev \ libclang-11-dev \ linux-head - $(uname -r )

$ curl - proto' = https' --tlsv1.2 -ssf https://sh.rustup.rs |谢。 〜/ .bashrc#或注销然后登录。$ Rustup安装夜晚$ Rustup默认夜晚$ rustc -version

$ sudo -i $ curl - proto' = https' --tlsv1.2 -ssf https://sh.rustup.rs | \ Env Rustup_home = / Opt / Rust / Rustup Cargo_Home = / Opt / Rust / Cargo \ Sh -s - --default-Toolchain稳定 - 新手默认--no-modify-path -y $ tee -a / root / .bashrc<<< hd#setup rose renceentexport rustup_home = / opt / rust / rustupExport路径= $ {path}:/ opt / rust / cargo / binhd $。 /root/.bashrc#或注销然后登录。$ Rustup安装夜间$ Rustup默认夜晚$ rustc -version

[包]名称=" xdp-ebpf-fw"版本=" 0.1.0" Edition =' 2018' [依赖关系] cty =" 0.2" Redbpf-macros =" 1.3" Redbpf-probes =" 1.3" [构建 - 依赖关系] Cargo-BPF = {Version =" 1.3" ,默认特征= false} [功能]默认= []探针= [] [lib] path =" src / lib.rs" [[bin]]名称=" fw"路径=" src / fw / main.rs"必需特征= ["探头"]

#![no_std]#![no_main]使用核心:: fmt ::错误;使用cty :: *;使用redbpf_probes :: xdp :: prelude :: *;程序! (0xFFFFFFFE," GPL"); const tcp_xdp_drop:xdpaction = xdpaction :: drop; const udp_xdp_drop:xdpaction = xdpaction :: drop; const xdp_pass:xdpaction = xdpaction :: pass; //基于XDP / EBPF的IP层防火墙删除所有UDP数据包。 //,也将所有TCP报文丢弃到端口80.#[XDP] PUB FN XDP_IP_FIREWALL(CTX:XDPContext) - > xdpresult {如果let确定(ip_protocol)= get_ip_protocol(& ctx){匹配ip_protocol,因为u32 {ipproto_udp =>返回OK(UDP_XDP_DROP),//将其放在底部IPPROTO_TCP => {如果let确定(传输)= ctx .transport(){如果传输.dest()== 80 {returne ok(tcp_xdp_drop); //将其放在地板上}}}}}} _ =>返回OK(XDP_PASS),//将其传递给协议栈}} return OK(XDP_PASS); //将协议栈} fn get_ip_protocol(ctx:& xdpcontext)传递给调情堆栈} fn get_ip_protocol - >结果< U32,错误> {如果LET OK(IP)= CTX .IP(){//我们需要将原始指针切入U32,所以需要不安全的方式。不安全{返回OK((* IP).PROTOCOLAS为U32); }} //以上的任何东西都保留。返回OK(0x10000); }

在Qemu上,我们需要添加2 n个队列(其中n是vcpus的数量)。以下<司机>在内部< interface&gt中需要部分。 (使用virsh编辑[vmname])是必需的(对于qemu版本4.2.1的4个vcpus,分配8次队列)。

< interface ...> [...]<驱动程序名称=' vhost' txmode =' iothread' ioeventfd ='' event_idx ='关闭'队列=' 8' rx_queue_size =' 256' tx_queue_size =' 256'> <宿主csum ='关闭' GSO =' OFF' tso4 ='关闭' TSO6 =' OFF' ECN =' OFF' UFO =' OFF' MRG_RXBUF =' OFF' /> < guest csum ='关闭' tso4 ='关闭' TSO6 =' OFF' ECN =' OFF' UFO =' off' />< />> [...]< / interface>

如果您喜欢这篇文章,请随时通过Buymeacoffee或Patreon支持我。谢谢你。