eBPF底层结构

文章介绍了CPU如何通过寄存器优化内存访问,特别关注了eBPF中的寄存器用途,如R0-R5和栈指针。讨论了eBPF程序如何通过BPFMAP进行用户空间和内核空间的数据交换,以及BPF_HASH和BPF_PERF_OUTPUT在数据处理和性能监控中的作用及其限制。
摘要由CSDN通过智能技术生成

寄存器: CPU不断读写内存是并不很快的, 这个速度好像还取决与对应的总线长度, 因此我们需要一个中间变量来帮助我们来快速访问对应的内存, 这个时候我们就需要使用到栈。

所以我们的寄存器, 通常分为下面几种:

  1. 数据寄存器, 一般用于存储数据
  2. 地址寄存器, 用于存储地址, 常见的有段指针

在eBPF中常见的寄存器有下面这几种:

  1. R0, 这个寄存器一般用于存储对应函数返回值
  2. R1-R5, 这几个寄存器用于存储函数的参数值
  3. R10, 这个寄存器的作用就是用来存放栈指针

一般两个程序如果想要交换信息, 一般可以通过两种方式:

  1. 一种是通过socket通信
  2. 第二种是通过共享内存

但是我们的eBPF有一个地方需要注意那就是, 我们的程序是会加载到内核中, 但是我们是在用户层, 所以需要一个媒介, 这个媒介就是BPF MAP。

这个BPF MAP提供了大块的存储在用户空间和内核空间, 这个map可以映射多种数据结构, 比如hashmap, 下面我为你演示了一下这个hashmap

BPF_HASH(counter_table);

int hello(void* ctx) {
    u64 uid;
    u64 counter = 0;
    u64* p;

    uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
    p = counter_table.lookup( &uid );

    if ( p != 0 ) {
        counter  = *p;
    }

    counter++;
    counter_table.update(&uid, &counter);

    return 0;
}

上面这段程序我使用了BPF_HASH()创建了一个hashmap, 这个map的类型是u64到u64上的, 但是这种东西有一个特点就是无法持续传输新的数据从我们的ebpf程序到用户, 这对持续记录事件是很影响的。

但是这种数据结构是比较适合数据的查找的, 比如内核向数据结构写一个数据, 然后我们可以通过应用程序取出对应的值

BPF_MAP_TYPE_PERF_EVENT_ARRAY,这个map函数是用来创建对应的ringbuffer的, 但是这个函数创建的东西是有限制的, 可能会导致内存的浪费, 事件的顺序无法得到一定的保证。

BPF_PERF_OUTPUT(output);

struct data_t {
    int pid;
    int uid;
    char command[16];
    char message[12];
};

int hello(void* ctx) {
    struct data_t data = {};
    char message[12] = "Hello, World";

    data.pid = bpf_get_current_pid_tgid() >> 32;
    data.uid = buf_get_curretn_uid_gid() & 0xFFFFFFFF;

    bpf_get_current_comm(&data.command, sizeof(data.command));
    bpf_probe_read_kernal(&data.message, sizeof(data.message), ,message);

    output.perf_submit(ctx, &data, sizeof(data));

    return 0;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值