我有以下eBPF计划:

#include <stdio.h>
#include <string.h>

#include <linux/bpf.h>
#include <sys/socket.h>

#include <bpf/bpf_helpers.h>

char LICENSE[] SEC("license") = "GPL";

// msg_data_map carries a key-value pair of (msg_id, msg_length), and can record
// upto 65535 messages at once.
#define MAX_MSG_LEN 128
struct {
  __uint(type, BPF_MAP_TYPE_HASH);
  __uint(max_entries, 65535);
  __type(key, int);
  __type(value, char[MAX_MSG_LEN]);
} msg_data_map SEC(".maps");

SEC("sk_msg")
int msg_prog(struct sk_msg_md *msg) {
  long len = (long)msg->data_end - (long)msg->data;

  void *data_end = (void *)(long) msg->data_end;
  void *data = (void *)(long) msg->data;

  // Bounds check to make verifier happy
  if (data + MAX_MSG_LEN > data_end) {
    return SK_PASS;
  }

  char buf[MAX_MSG_LEN] = {0};
  if (len > MAX_MSG_LEN) {
    __builtin_memcpy(buf, data, MAX_MSG_LEN);
  } else {
    __builtin_memcpy(buf, data, len);
  }

  // Update in map
  int index = 0;
  bpf_map_update_elem(&msg_data_map, &index, &buf, BPF_ANY);
 
  return SK_PASS;
}

编译上述程序会出现以下错误:

Looks like the BPF stack limit of 512 bytes is exceeded. Please move large on stack variables into BPF per-cpu array map.
  1. 因为buf数组只有128个字节,所以它不应该超过堆栈限制.
  2. 如果我注释 map 更新行,程序编译得很好.为何会是这样呢?

推荐答案

错误消息

看起来超过了512字节的BPF堆栈限制.请将堆栈上的大变量移到BPF每CPU数组映射中.

也被记录在bpftrace中,https://github.com/iovisor/bpftrace/blob/master/docs/internals_development.md#stack-limit-exceeded

它似乎是错误normally thrown by the kernel的更好的版本

%d个调用的组合堆栈大小为%d.太大 但我找不到这个更好的版本实际上是从哪里来的.无论如何,这都是一个合理的错误.验证器强制每个堆栈帧(每个BPF到BPF函数)512字节stack limit.

消除此错误的唯一方法是减少堆栈上的变量数量.该错误建议使用每CPU映射来存储堆栈中当前的一些数据,因为BPF程序不会被抢占,因此可以使用映射值,而不必担心与其他程序冲突.

我应该注意到,在RT(实时)内核上,这种关于每CPU映射的假设是不正确的,因为BPF程序永远不会迁移,但仍然可以被抢占.

C++相关问答推荐

如何避免使用相对路径包含在c中

当包含头文件时,gcc会发出隐式函数声明警告

位屏蔽对于无符号转换是强制的吗?

Apple Libm的罪恶功能

了解一些CLIPS原语数据类型

核心转储文件中出现奇怪的大小变化

为什么内核使用扩展到前后相同的宏定义?

C是否用0填充多维数组的其余部分?

如何在不使用其他数组或字符串的情况下交换字符串中的两个单词?

为什么GDB/MI进程的FIFO循环中有read()阻塞

如何识别Linux中USB集线器(根)和连接到集线器(根设备)的设备(子设备)?

对于C中给定数组中的每个查询,如何正确编码以输出给定索引范围(1到N)中所有数字的总和?

Flose()在Docker容器中抛出段错误

为什么我可以在GCC的标签后声明变量,但不能声明Clang?

正数之和是负数

是否定义了此函数的行为?

用C++构建和使用DLL的困惑

为什么电路板被循环删除?

C: NULL>;NULL总是false?

cs50拼写器分配中的无限循环