2

我在用户端使用多生产者单消费者实现来处理来自 XDP 挂钩的 eBPF 映射的传入数据。

但是,为了做到这一点,我需要将 XDP 挂钩用于向用户空间发送信息的核心数量限制为 1。

我们有办法做到这一点吗?

我正在使用 BPF_MAP_TYPE_PERF_EVENT_ARRAY,并通过 bpf_prog_load_xattr 和 bpf_set_link_xdp_fd 挂钩 kern 代码。

这是加载钩子的函数。

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

0 回答 0