0

I try to get the fd of the BPF_MAP_TYPE_XSKMAP in my user-space program.

This is the code:

ret = bpf_get_link_xdp_id(cfg->ifindex, &cfg->prog_id, cfg->xdp_flags);
if (ret) {
    fprintf(stderr, "`bpf_get_link_xdp_id` returned error: %s\n", strerror(errno));
    exit(-ret);
}

cfg->prog_fd = bpf_prog_get_fd_by_id(cfg->prog_id);
if(cfg->prog_fd < 0) {
    fprintf(stderr, "Failed to obtain prog_fd: %s\n", strerror(errno));
    exit(1);
}

struct bpf_prog_info prog_info;
uint32_t prog_info_len = sizeof(struct bpf_prog_info);
uint32_t map_info_len = sizeof(struct bpf_map_info);
if(bpf_obj_get_info_by_fd(cfg->prog_fd, &prog_info, &prog_info_len) == 0) {

    const uint32_t amnt_of_maps = prog_info.nr_map_ids;
    uint32_t *map_ids = (uint32_t*)malloc(sizeof(uint32_t) * prog_info.nr_map_ids);

    memset(&prog_info, 0, prog_info_len);
    prog_info.nr_map_ids = amnt_of_maps;
    prog_info.map_ids = (uint64_t)(unsigned long)map_ids;

    if(bpf_obj_get_info_by_fd(cfg->prog_fd, &prog_info, &prog_info_len) == 0) {

        for(uint32_t i = 0; i < prog_info.nr_map_ids; i++) {

            const int map_fd = bpf_map_get_fd_by_id(map_ids[i]);

            if(map_fd >= 0) {
                struct bpf_map_info map_info;
                if(bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len) == 0) {
                    if(strcmp(map_info.name, "xsks_map") == 0) {
                        cfg->xsks_map_fd = map_fd;
                        printf("Got fd of xsks_map!\n");
                        break;
                    }
                } else {
                    close(map_fd);
                }
            } else {
                fprintf(stderr, "Failed to obtain map_fd for id %d: %s\n", i, strerror(errno));
            }

        }
    } else {
        fprintf(stderr, "Failed to obtain prog_info 2: %s\n", strerror(errno));
    }
} else {
    fprintf(stderr, "Failed to obtain prog_info 1: %s\n", strerror(errno));
}

But unfortunately, I get an error for calling bpf_obj_get_info_by_fd(cfg->prog_fd, &prog_info, &prog_info_len): Failed to obtain prog_info 1: Invalid argument.

I don't know if this is because the XDP-program is loaded from another process? Does the same process have to obtain program information which also loaded the AF-XDP program?

Edit: The only thing I changed in my user-space program was to populate a BPF_MAP_TYPE_HASH via bpf_map_update_elem (the entries are in there, observed with bpftool map dump id <id>) and to use bpf_map_lookup_elem in my XDP-program (same hash map).

And suddenly, the error changes to: Failed to obtain prog_info 1: Bad address

binaryBigInt
  • 1,526
  • 2
  • 18
  • 44
  • It shouldn't have to be in the same process, which you could check by printing the id you get from `bpf_get_link_xdp_id()` and trying to feed it to `bpftool prog show id ` for example. I don't know why the call to `bpf_prog_get_fd_by_id()` failed. Are you using the latest version of libbpf? Using an old version seems to be the best candidate for [`-EINVAL`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/bpf/syscall.c?h=v5.5#n2314) – Qeole Mar 12 '20 at 14:30
  • Thanks for your comment. I just copied the latest version from libbpf-github repo (last commit on March 11th). I know it sounds strange, but sometimes this code works without an error and sometimes it doesn't (restarting my program helps). I know you or others can't do much with that vague statement. – binaryBigInt Mar 12 '20 at 15:53
  • “Sometimes this code works without an error and sometimes it doesn't” -> Do you mean with the latest libbpf, or before that? What do you get with latest libbpf? Any difference you can observe with `strace -e bpf` between successful and aborted runs? – Qeole Mar 12 '20 at 16:26
  • I mean with latest libbpf. I get libbpf from here: https://github.com/libbpf/libbpf. I made some edits to my original posting. Is there a unknown sequence of function calls which has to be satisfied in order to make these bpf-calls work, e.g. don't populate a map before calling `bpf_obj_get_info_by_fd`? – binaryBigInt Mar 13 '20 at 08:35
  • Sorry, I misread. I thought the error was coming from `bpf_prog_get_fd_by_id()` instead of the call to `bpf_obj_get_info_by_fd()`. – Qeole Mar 13 '20 at 10:08

1 Answers1

1

There is a comment in a function from the kernel code called when you try to retrieve information about your program, stating:

/* If we're handed a bigger struct than we know of, ensure all the unknown bits are 0 - i.e. new user-space does not rely on any kernel feature extensions we don't know about yet. [...] */

I think this is what you hit in your case. Your libbpf version might use some attributes in struct bpf_prog_info that the kernel is not aware of.

To ensure that the kernel accepts it, simply try to zero-initialise your struct:

struct bpf_prog_info prog_info = {};
Qeole
  • 8,284
  • 1
  • 24
  • 52