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;
}