Получить PID XDP-хука в пользовательском пространстве - PullRequest
1 голос
/ 21 января 2020

Я использую многопользовательскую реализацию для одного потребителя на стороне пользователя для обработки входящих данных из карты eBPF из ловушки XDP.

Однако для этого мне нужно ограничить количество ядер, которое может использовать ловушка XDP для отправки информации в пространство пользователя по одному. Из того, что я понимаю, единственный способ сделать это - установить его сродство таким образом:

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