Krzysztof Michalak
Krzysztof Michalak

Reputation: 21

Sharing bpf map between two independent programs

I'm quite new into BPF. I wanted to create 2 small simple programs to learn how to share bpf map between programs.

So I created user space program

//user_space.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/bpf.h>
#include <bpf/libbpf.h>
#include <signal.h>

struct bpf_object *obj;

// Signal handler to handle Ctrl+C
void cleanup_and_exit(int sig) {
    fprintf(stderr, "Received signal %d. Cleaning up...\n", sig);

    if (obj) {
        bpf_object__close(obj);
    }

    exit(0);
}

int main(void) {
    // Install the signal handler
    signal(SIGINT, cleanup_and_exit);

    // Create BPF map
    struct bpf_map *map;

    obj = bpf_object__open_file("bpf_program.o", NULL);

    if (!obj) {
        fprintf(stderr, "Error loading BPF object file\n");
        return 1;
    }

    map = bpf_map__next(NULL, obj);
    if (!map) {
        fprintf(stderr, "Error finding BPF map\n");
        bpf_object__close(obj);
        return 1;
    }

    // Update map attributes
    bpf_map__set_type(map, BPF_MAP_TYPE_HASH);
    bpf_map__set_key_size(map, sizeof(int));
    bpf_map__set_value_size(map, sizeof(long));
    bpf_map__set_max_entries(map, 1024);

    // Load BPF object and create the map
    if (bpf_object__load(obj)) {
        fprintf(stderr, "Error loading BPF object\n");
        bpf_object__close(obj);
        return 1;
    }

    printf("BPF map created and loaded successfully\n");

    // Print the file descriptor of the map
    printf("File Descriptor of BPF map: %d\n", bpf_map__fd(map));

    // Insert a value into the map
    int key = 42;
    long value = 123;

    if (bpf_map_update_elem(bpf_map__fd(map), &key, &value, BPF_ANY) != 0) {
        perror("Error inserting value into BPF map");
        bpf_object__close(obj);
        return 1;
    }

    printf("Value inserted into BPF map successfully\n");

    // Keep the program running
    while (1) {
        sleep(1);
    }

    return 0;
}

and BPF program for it

// bpf_program.c

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct bpf_map_def SEC("maps") my_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(int),
    .value_size = sizeof(long),
    .max_entries = 1024,
};

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

and second user space program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>

#define MAX_ENTRIES 1024

int main(void) {
    // Open the BPF object file
    struct bpf_object *obj;

    obj = bpf_object__open_file("bpf_program1.o", NULL);
    if (!obj) {
        fprintf(stderr, "Error opening BPF object file: %s\n", strerror(errno));
        return 1;
    }

    // Load the BPF object
    if (bpf_object__load(obj)) {
        fprintf(stderr, "Error loading BPF object: %s\n", strerror(errno));
        bpf_object__close(obj);
        return 1;
    }

    // Find the map by name
    struct bpf_map *map = bpf_object__find_map_by_name(obj, "my_map");
    if (!map) {
        fprintf(stderr, "Error finding BPF map by name: %s\n", strerror(errno));
        bpf_object__close(obj);
        return 1;
    }

    // Retrieve the file descriptor of the BPF map
    int map_fd = bpf_map__fd(map);
    if (map_fd < 0) {
        fprintf(stderr, "Error obtaining file descriptor for BPF map: %s\n", strerror(errno));
        bpf_object__close(obj);
        return 1;
    }

    printf("BPF map found successfully with FD: %d\n", map_fd);

    // Reuse the BPF map file descriptor
    if (bpf_map__reuse_fd(map, map_fd) != 0) {
        fprintf(stderr, "Error reusing BPF map file descriptor: %s\n", strerror(errno));
        bpf_object__close(obj);
        return 1;
    }

    // Allocate memory for keys and values
    int keys[MAX_ENTRIES];
    long values[MAX_ENTRIES];

    // Declare 'next_key' before the loop
    int next_key;

    // Iterate over all entries in the BPF map
    int key;
    long value;
    int i = 0;

    while (bpf_map_get_next_key(map_fd, &key, &next_key) == 0) {
        if (bpf_map_lookup_elem(map_fd, &key, &value) == 0) {
            keys[i] = key;
            values[i] = value;
            i++;
        }
        key = next_key;
    }

    // Print all key-value pairs
    printf("All values in the BPF map:\n");
    for (int j = 0; j < i; j++) {
        printf("Key: %d, Value: %ld\n", keys[j], values[j]);
    }

    // Keep the program running
    sleep(10);

    // Clean up
    bpf_object__close(obj);

    return 0;
}

and bpf program for second program

// bpf_program1.c

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct bpf_map_def SEC("maps") my_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(int),
    .value_size = sizeof(long),
    .max_entries = 1024,
};

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

Both of this programs compile and run but they are create own instances of maps rather than sharing the same map. I think probably I made a mistake in second user space program and creating from file descriptor. Thanks in advance for help and your time.

Upvotes: 2

Views: 400

Answers (1)

Said Jawad
Said Jawad

Reputation: 48

One way of sharing maps between programs is using pinning, e.g., pinning by name. In libbpf, you can do this by setting the corresponding flag in the map definition. So in your bpf programs change the map definition to something as following:

    struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __type(key, int);
    __type(value, long);
    __uint(max_entries, 1024);
    __uint(pinning, LIBBPF_PIN_BY_NAME);
} my_map SEC(".maps");

This is a possible duplicate of this question: Sharing ebpf maps between 2 interface

Upvotes: 1

Related Questions