C语言 在eBPF中不断增加MapID

14ifxucb  于 2023-06-28  发布在  其他
关注(0)|答案(1)|浏览(96)

我正在运行eBPF sockops程序。在测试过程中,我需要多次加载和重新加载程序。
下面是我用来加载和附加BPF程序的用户空间程序:

static const char *__doc__ = "User space program to load the sockops bpf program to register sockets\n";

#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

const char *cgroup_dir = "/sys/fs/cgroup/unified";

int main(int argc, char **argv) {
  int err, len;
  int cgroup_fd;
  const char *sockops_file = "bpf_sockops.o";
  struct bpf_object *sockhash_obj;
  bool do_unload = false;

  // Open the cgroup fd -- needed for both attach and detach operations.
  fprintf(stdout, "Opening cgroup file %s\n", cgroup_filename);
  cgroup_fd = open(cgroup_dir, O_RDONLY);
  if (cgroup_fd < 0) {
    fprintf(stderr, "ERR: opening cgroup file %s\n", strerror(errno));
    goto exit_cgroup;
  }

  // Check if the program is to be unloaded.
  if (do_unload) {
    // Unload the sockops program
    err = bpf_prog_detach(cgroup_fd, BPF_CGROUP_SOCK_OPS);
    if (err) {
      goto fail;
    }

    return 0;
  }

  // Open, load and attach sockops_obj if not already attached
  sockhash_obj = bpf_object__open_file(sockops_file, NULL);
  if (libbpf_get_error(sockhash_obj)) {
    goto fail;
  }

  struct bpf_program *sockops_prog = bpf_object__find_program_by_name(sockhash_obj, "bpf_add_to_sockhash");
  if (!sockops_prog) {
    goto fail;
  }

  // Load the sockops program
  err = bpf_object__load(sockhash_obj);
  if (err) {
    goto fail;
  }

  // Attach the sockops program
  // Using core BPF API as libbpf doesn't support sockops yet.
  err = bpf_prog_attach(bpf_program__fd(sockops_prog), cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
  if (err) {
    fprintf(stderr, "ERR: attaching program\n");
    goto fail;
  }

  fprintf(stdout, "Successfully loaded BPF program.\n");

  return 0;

exit_cgroup:
  close(cgroup_fd);

fail:
  return -1;
}

我将sockops程序从用户空间程序中附加/分离的关键调用是:

err = bpf_prog_attach(bpf_program__fd(sockops_prog), cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
...
...
...
err = bpf_prog_detach(cgroup_fd, BPF_CGROUP_SOCK_OPS);

我的sockops程序看起来像:

// File Name: bpf_sockops.c
#include <linux/in.h>
#include <linux/tcp.h>

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

#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>

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

// sock_ops_map maps the sock_ops key to a socket descriptor
struct {
  __uint(type, BPF_MAP_TYPE_SOCKHASH);
  __uint(max_entries, 65535);
  __type(key, struct sock_key);
  __type(value, __u64);
} sock_ops_map SEC(".maps");

// `sock_key' is a key for the sockmap
struct sock_key {
  __u32 sip4;
  __u32 dip4;
  __u32 sport;
  __u32 dport;
} __attribute__((packed));

// `sk_extract_key' extracts the key from the `bpf_sock_ops' struct
static inline void sk_extract_key(struct bpf_sock_ops *ops,
                                  struct sock_key *key) {
  key->dip4 = ops->remote_ip4;
  key->sip4 = ops->local_ip4;
  key->sport = (bpf_htonl(ops->local_port) >> 16);
  key->dport = ops->remote_port >> 16;
}

SEC("sockops")
int bpf_add_to_sockhash(struct bpf_sock_ops *skops) {
  __u32 family, op;

  family = skops->family;
  op = skops->op;
  bpf_printk("Got new operation %d for socket.\n", op);

  switch (op) {
    case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
    case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
      if (family == AF_INET) {
        struct sock_key key = {};
        sk_extract_key(skops, &key);
        int ret = bpf_sock_hash_update(skops, &sock_ops_map, &key, BPF_NOEXIST);
        if (ret != 0) {
          bpf_printk("Failed to update sockmap: %d\n", ret);
        } else {
          bpf_printk("Added new socket to sockmap\n");
        }
      }
      break;
    default:
      break;
  }
  return 0;
}

当我重新加载程序几次时,sock_ops_map的map id不断增加:

~/ebpf-code$ sudo bpftool prog show
1751: cgroup_skb  tag 6deef7357e7b4530  gpl
        loaded_at 2023-06-21T23:42:28-0600  uid 0
        xlated 64B  jited 54B  memlock 4096B
1752: cgroup_skb  tag 6deef7357e7b4530  gpl
        loaded_at 2023-06-21T23:42:28-0600  uid 0
        xlated 64B  jited 54B  memlock 4096B
1753: cgroup_skb  tag 6deef7357e7b4530  gpl
        loaded_at 2023-06-21T23:42:28-0600  uid 0
        xlated 64B  jited 54B  memlock 4096B
1754: cgroup_skb  tag 6deef7357e7b4530  gpl
        loaded_at 2023-06-21T23:42:28-0600  uid 0
        xlated 64B  jited 54B  memlock 4096B
1755: cgroup_skb  tag 6deef7357e7b4530  gpl
        loaded_at 2023-06-21T23:42:28-0600  uid 0
        xlated 64B  jited 54B  memlock 4096B
1756: cgroup_skb  tag 6deef7357e7b4530  gpl
        loaded_at 2023-06-21T23:42:28-0600  uid 0
        xlated 64B  jited 54B  memlock 4096B
1762: sock_ops  name bpf_add_to_sock  tag 79fcc2296545280f  gpl
        loaded_at 2023-06-21T23:53:36-0600  uid 0
        xlated 880B  jited 521B  memlock 4096B  map_ids 1219,1217,1220
        btf_id 1554

如上所示,Mapid已经是1217-1220。是否预期MapID会持续增加?当达到限制(或最大MapID)时会发生什么?

2ul0zpep

2ul0zpep1#

是否预期MapID会持续增加?
一旦对Map的最后一次引用消失,Map就被卸载。因此,当您使用bpf_prog_detach分离旧程序时,也会导致Map被卸载。然后,当您bpf_object__load时,您重新创建Map,从而增加其ID。
所以这取决于你的目标,如果这是预期或不。如果您不希望发生这种情况,可以执行以下操作:
在程序重新加载时保持Map的最简单方法是固定Map。你可以通过在Map上设置pinning字段来实现:

struct {
  __uint(type, BPF_MAP_TYPE_SOCKHASH);
  __uint(max_entries, 65535);
  __type(key, struct sock_key);
  __type(value, __u64);
  __uint(pinning, LIBBPF_PIN_BY_NAME);
} sock_ops_map SEC(".maps");

使用bpf_object__open_file打开对象文件时,需要指定固定路径。你必须设置opts->pin_root_path
当达到限制(或最大MapID)时会发生什么?
id将增加到(1 << 32)-1,然后翻转并从头开始,内核将重新使用不再使用的id,但如果id仍然存在,则从不重新使用id

相关问题