Linux内核工程导论——网络:Filter(LSF、BPF、eBPF)

Linux内核工程导论——网络:Filter(LSF、BPF、eBPF)概览 LSF Linuxsocketf 起源于 BPF BerkeleyPack 基础从架构一致 但使用更简单

大家好,欢迎来到IT知识分享网。

概览

bpf主要用途

    其核心原理是对用户提供了两种SOCKET选项:SO_ATTACH_FILTER和SO_ATTACH_BPF。允许用户在某个sokcet上添加一个自定义的filter,只有满足该filter指定条件的数据包才会上发到用户空间。因为sokect有很多种,你可以在各个维度的socket添加这种filter,如果添加在raw socket,就可以实现基于全部IP数据包的过滤(tcpdump就是这个原理),如果你想做一个http分析工具,就可以在基于80端口(或其他http监听端口)的socket添加filter。还有一种使用方式离线式的,使用libpcap抓包存储在本地,然后可以使用bpf代码对数据包进行离线分析,这对于实验新的规则和测试bpf程序非常有帮:SO_ATTACH_FILTER插入的是cBPF代码,SO_ATTACH_BPF插入的是eBPF代码。eBPF是对cBPF的增强,目前用户端的tcpdump等程序还是用的cBPF版本,其加载到内核中后会被内核自动的转变为eBPF。

echo 2 > /proc/sys/net/core/bpf_jit_enable

通过像这个写入0/1/2可以实现关闭、打开、调试日志等bpf模式。

其他的BPF程序

    前面说的bpf程序是用来做包过滤的,那么bpf代码只能用来做包过滤吗?非也。内核的bpf支持是一种基础架构,只是一种中间代码的表达方式,是向用户空间提供一个向内核注入可执行代码的公共接口。只是目前的大部分应用是使用这个接口来做包过滤。其他的如seccomp BPF可以用来实现限制用户进程可使用的系统调用,cls_bpf可以用来将流量分类,PTP dissector/classifier(干啥的还不知道)等都是使用内核的eBPF语言架构来实现各自的目的,并不一定是包过滤功能。

用户空间bpf支持

工具:tcpdump、tools/net、cloudfare、seccomp BPF、IO visitor、ktap

cBPF汇编架构分析

    cBPF中每一条汇编指令都是如下格式:

struct sock_filter { /* Filter block */ __u16 code; /* Actual filter code */ __u8 jt; /* Jump true */ __u8 jf; /* Jump false */ __u32 k; /* Generic multiuse field */ };
 A 32位,所有加载指令的目的地址和所有指令运算结果的存储地址 X 32位,二元指令计算A中参数的辅助寄存器(例如移位的位数,除法的除数) M[] 0-151632位寄存器,可以自由使用

    我们最常见的用法莫过于从数据包中取某个字的数据内来做判断。按照bpf的规定,我们可以使用偏移来指定数据包的任何位置,而很多协议很常用并且固定,例如端口和ip地址等,bpf就为我们提供了一些预定义的变量,只要使用这个变量就可以直接取值到对应的数据包位置。例如:

len skb->len proto skb->protocol type skb->pkt_type poff Payload start offset ifidx skb->dev->ifindex nla Netlink attribute of type X with offset A nlan Nested Netlink attribute of type X with offset A mark skb->mark queue skb->queue_mapping hatype skb->dev->type rxhash skb->hash cpu raw_smp_processor_id() vlan_tci skb_vlan_tag_get(skb) vlan_avail skb_vlan_tag_present(skb) vlan_tpid skb->vlan_proto rand prandom_u32()

更可贵的是这个列表还可以由用户自己去扩展。各种bpf引擎的具体实现还会定义各自的扩展。

eBPF汇编架构分析

struct bpf_insn { __u8 code; /* opcode */ __u8 dst_reg:4; /* dest register */ __u8 src_reg:4; /* source register */ __s16 off; /* signed offset */ __s32 imm; /* signed immediate constant */ };

其寄存器也不同:

 * R0 - return value from in-kernel function, and exit value for eBPF program * R1 - R5 - arguments from eBPF program to in-kernel function * R6 - R9 - callee saved registers that in-kernel function will preserve * R10 - read-only frame pointer to access stack

eBPF的数据交互:map

BPF_MAP_TYPE_HASH, //hash类型 BPF_MAP_TYPE_ARRAY, //数组类型 BPF_MAP_TYPE_PROG_ARRAY, //程序表类型

eBPF的直接编程方法

    除了在用户空间通过nettable和tcpdump来使用bpf,在内核中或者在其他通用的编程中可以直接使用C写eBPF代码,但是需要LLVM支持,例子。

内核的C辅助函数支持

#include <linux/bpf.h> int bpf(int cmd, union bpf_attr *attr, unsigned int size);

内核中与bpf相关的内核模块子系统

bpf用于内核TRACING

    我们知道eBPF有map数据结构,有程序执行能力。那么这就是完美的跟踪框架。比如通过kprobe将一个eBPF程序插入IO代码,监控IO次数,然后通过map向用户空间汇报具体的值。用户端只需要每次使用bpf系统调用查看这个map就可以得到想要统计的内容了。那么为何要用eBPF,而不是直接使用kprobe的c代码本身呢?这就是eBPF的安全性,其机制设计使其永远不会crash掉内核,不会与正常的内核逻辑发生交叉影响。可以说,通过工具选择避免了可能发生的很多问题。更可贵的是eBPF是原生的支持tracepoint,这就为kprobe不稳定的情况提供了可用性。

业界对eBPF的tracing使用

意义和总结

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/116983.html

(0)
上一篇 2025-11-24 19:15
下一篇 2025-11-24 19:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信