Reputation: 21
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
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