我正在运行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)时会发生什么?
1条答案
按热度按时间2ul0zpep1#
是否预期MapID会持续增加?
一旦对Map的最后一次引用消失,Map就被卸载。因此,当您使用
bpf_prog_detach
分离旧程序时,也会导致Map被卸载。然后,当您bpf_object__load
时,您重新创建Map,从而增加其ID。所以这取决于你的目标,如果这是预期或不。如果您不希望发生这种情况,可以执行以下操作:
在程序重新加载时保持Map的最简单方法是固定Map。你可以通过在Map上设置
pinning
字段来实现:使用
bpf_object__open_file
打开对象文件时,需要指定固定路径。你必须设置opts->pin_root_path
。当达到限制(或最大MapID)时会发生什么?
id将增加到(1 << 32)-1,然后翻转并从头开始,内核将重新使用不再使用的id,但如果id仍然存在,则从不重新使用id