我在用户端使用多生产者单消费者实现来处理来自 XDP 挂钩的 eBPF 映射的传入数据。
但是,为了做到这一点,我需要将 XDP 挂钩用于向用户空间发送信息的核心数量限制为 1。据我了解,这样做的唯一方法是以如下方式设置其亲和力:
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
CPU_SET(2, &mask);
sched_setaffinity(-1, sizeof(mask), &mask);
但是,我不知道如何获取我的钩子的 PID,以便我可以做到这一点。
我正在使用,并通过和BPF_MAP_TYPE_PERF_EVENT_ARRAY
挂钩紧缩代码。bpf_prog_load_xattr
bpf_set_link_xdp_fd
这是加载钩子的函数。
static int do_attach(int idx, int fd, const char *name, __u32 xdp_flags)
{
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
int err;
err = bpf_set_link_xdp_fd(idx, fd, xdp_flags);
if (err < 0) {
printf("ERROR: failed to attach program to %s\n", name);
return err;
}
err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
if (err) {
printf("can't get prog info - %s\n", strerror(errno));
return err;
}
prog_id = info.id;
return err;
}
这是它被使用的地方。
int main(int argc, char **argv)
{
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
struct bpf_prog_load_attr prog_load_attr = {
.prog_type = BPF_PROG_TYPE_XDP,
};
int prog_fd, map_fd;
struct bpf_object *obj;
struct bpf_map *map;
char filename[256];
int ret, err, i;
int numcpus = bpf_num_possible_cpus();
struct config cfg = {
.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE,
.ifindex = -1,
};
strncpy(cfg.filename, default_filename, sizeof(cfg.filename));
/* Cmdline options can change these */
parse_cmdline_args(argc, argv, long_options, &cfg, __doc__);
/* Required option */
if (cfg.ifindex == -1) {
fprintf(stderr, "ERR: required option --dev missing\n");
usage(argv[0], __doc__, long_options, (argc == 1));
return EXIT_FAIL_OPTION;
}
if (setrlimit(RLIMIT_MEMLOCK, &r)) {
perror("setrlimit(RLIMIT_MEMLOCK)");
return 1;
}
snprintf(filename, sizeof(filename), "xdp_sample_pkts_kern.o");
prog_load_attr.file = filename;
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
if (!prog_fd) {
printf("load_bpf_file: %s\n", strerror(errno));
return 1;
}
map = bpf_map__next(NULL, obj);
if (!map) {
printf("finding a map in obj file failed\n");
return 1;
}
map_fd = bpf_map__fd(map);
err = do_attach(cfg.ifindex, prog_fd, cfg.ifname, cfg.xdp_flags);
if (err)
return err;
if (signal(SIGINT, sig_handler) ||
signal(SIGHUP, sig_handler) ||
signal(SIGTERM, sig_handler)) {
perror("signal");
return 1;
}
test_bpf_perf_event(map_fd, numcpus);
for (i = 0; i < numcpus; i++)
if (perf_event_mmap_header(pmu_fds[i], &headers[i]) < 0)
return 1;
pd = pcap_open_dead(DLT_EN10MB, 65535);
if (!pd)
goto out;
pdumper = pcap_dump_open(pd, cfg.filename);
if (!pdumper)
goto out;
ret = perf_event_poller_multi(pmu_fds, headers, numcpus,
print_bpf_output, &done);
pcap_dump_close(pdumper);
pcap_close(pd);
out:
do_detach(cfg.ifindex, cfg.ifname);
printf("\n%u packet samples stored in %s\n", pcap_pkts, cfg.filename);
return ret;
}