I have a bpf program storing some stats in a map via BPF_TYPE_MAP_ARRAY. That side of code seems to works correctly, I can use bpftool to see my map.
# bpftool map show
31: array  name xdp_stats_map  flags 0x0
        key 4B  value 16B  max_entries 16  memlock 4096B
# bpftool map dump id 31
key: 00 00 00 00  value: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
key: 01 00 00 00  value: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
key: 02 00 00 00  value: e3 a6 00 00 00 00 00 00  99 38 b3 00 00 00 00 00
key: 03 00 00 00  value: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
[...] 
We can see some data on key 2 and theses data are updated correctly. However when I try to collect theses data in userspace with libbpf, I only have null values. I have no clue what's wrong.
If I fake the fd, call fails, if I try to fetch more than 16 elements, it fails later, so everything sounds correct.
struct counters {
    __u64 rx_packets;
    __u64 rx_bytes;
};
void dies(char *str) {
    fprintf(stderr, "[-] %s", str);
    exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
    struct counters value;
    char *filename = "./xdp_pass.o";
    int fd;
    if(argc > 1)
        filename = argv[1];
    struct bpf_object *obj = bpf_object__open(filename);
    if(libbpf_get_error(obj))
        dies("could not open bpf object");
    bpf_object__load(obj);
    if(libbpf_get_error(obj))
        dies("could not load bpf object");
    if((fd = bpf_object__find_map_fd_by_name(obj, "xdp_stats_map")) < 0)
        dies("could not find map in the object");
    for(__u32 key = 0; key < 16; key++) {
        if((bpf_map_lookup_elem(fd, &key, &value)) != 0)
            dies("could not key in map");
        printf("ID % 3d: %llu, %llu\n", key, value.rx_packets, value.rx_bytes);
    }
    return 0;
}
Returns:
ID   0: 0, 0
ID   1: 0, 0
ID   2: 0, 0
ID   3: 0, 0
ID   4: 0, 0
[...] (all zero)