reading updated value of ebpf's BPF_MAP_TYPE_HASH in userspace | Can read() linux function be used to get current value of object shared through map

So I have a kernel ebpf program that attach xdp hook to interface eno1, and in it I have a map ip_map that is of type BPF_MAP_TYPE_HASH that I am sharing with userspace. So in my userspace I am getting map's file descriptor, But now I like to get updated values of struct share_me which I am sharing with the help of BPF_MAP_TYPE_HASH type map in my userspace loader program.

Any anyone please help me explain a bit, as to how I can do this,

So I am assuming if my map_fd is pointing to BPF_MAP_TYPE_HASH is pointing to my MAP then I can just do this int sizeof_share_me_read=read(map_fd,&share_me,sizeof(struct share_me)); so this way I can read current updated value of my map_fd(BPF_MAP_TYPE_HASH) shared from kernel ebpf program and that will contain current packet's ip header in struct iphdr dest_ip member of share_me object. Can any one please help me sort this out

user.c

/* SPDX-License-Identifier: GPL-2.0 */

#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include <sys/resource.h>

#include <bpf/bpf.h>
#include <bpf/xsk.h>

#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if_link.h>
#include <linux/if_ether.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>


#include "../common/common_params.h"
#include "../common/common_user_bpf_xdp.h"
#include "../common/common_libbpf.h"


int main()
{
    struct bpf_object *bpf_obj;
    struct bpf_program *bpf_prog;
    bpf_obj = load_bpf_object_file("af_xdp_kern.o", 0);
    if (!bpf_obj) {
        printf("ERR: loading file:\n");
        exit(EXIT_FAIL_BPF);
    }
             bpf_prog = bpf_program__next(NULL, bpf_obj);
    if (!bpf_prog)
    {
        printf("bpf_program_next:\n");
        exit(0);    
    }
    int prog_fd = bpf_program__fd(bpf_prog);
    if (prog_fd <= 0) {
    }
    int err = xdp_link_attach(if_nametoindex("eno1"), 0, prog_fd);
    if(err)
    {
        printf("xdp_link_attach\n");
        exit(0);
    }   
    struct bpf_map *map1 = bpf_object__find_map_by_name(bpf_obj, "ip_map");
    int map_fd = bpf_map__fd(map1);
    if(map_fd<0)
    {
        printf("map fd <0\n");
        exit(0);

    }
            
    return 0;

}

kernel.c

/* SPDX-License-Identifier: GPL-2.0 */

#include <linux/bpf.h>

#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
void *memcpy(void *, const void *, unsigned long);

int IPPROTO_UDP = 17;

struct share_me
{

    struct iphdr dest_ip;
};

struct bpf_map_def SEC("maps") ip_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(int),
    .value_size = sizeof(struct share_me),
    .max_entries = 64,  /* Assume netdev has no more than 64 queues */
};

struct bpf_map_def SEC("maps") xsks_map = {
    .type = BPF_MAP_TYPE_XSKMAP,
    .key_size = sizeof(int),
    .value_size = sizeof(int),
    .max_entries = 64,  /* Assume netdev has no more than 64 queues */
};



struct bpf_map_def SEC("maps") xdp_stats_map = {
    .type        = BPF_MAP_TYPE_PERCPU_ARRAY,
    .key_size    = sizeof(int),
    .value_size  = sizeof(__u32),
    .max_entries = 64,
};

SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx)
{
    int index = ctx->rx_queue_index;
    __u32 *pkt_count;

    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    struct share_me me;

    if ((void *)eth + sizeof(*eth) <= data_end)
    {

        struct iphdr *ip = data + sizeof(*eth);
        //me.dest_ip=ip;
        

        if(((void *)ip+sizeof(*ip))<=data_end)
        {   
             struct iphdr ip_temp=(struct iphdr)*ip;            
            memcpy(&me.dest_ip,&ip_temp,sizeof(ip_temp));
            bpf_map_lookup_elem(&ip_map, &index);
            bpf_map_update_elem(&ip_map,&index,&me,0);
            if ((void *)ip + sizeof(*ip) <= data_end)
            {

                if (ip->protocol == IPPROTO_UDP)
                {

           struct udphdr *udp = (void *)ip + sizeof(*ip);
           if ((void *)udp + sizeof(*udp) <= data_end)
           {
               //u64 value = htons(udp->dest);
               //counter.increment(value);
           }
                }
            }
         }  
    }



    pkt_count = bpf_map_lookup_elem(&xdp_stats_map, &index);
    if (pkt_count) {

        /* We pass every other packet */
        if ((*pkt_count)++ & 1)
            return XDP_DROP;
    }

    /* A set entry here means that the correspnding queue_id
     * has an active AF_XDP socket bound to it. */
    if (bpf_map_lookup_elem(&xsks_map, &index))
        return bpf_redirect_map(&xsks_map, index, 0);

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

Solution 1:

Now that you have the map fd, you need to use libbpf's bpf_map_lookup_elem function to read the values:

int key = 0;
struct share_me value = {};
if (bpf_map_lookup_elem(map_fd, &key, &value))
    // Print errno.