Skip to content

Instantly share code, notes, and snippets.

@pldubouilh
Last active February 28, 2023 13:47
Show Gist options
  • Save pldubouilh/9f98cf2b5a4e0ba5676cab111ec3728b to your computer and use it in GitHub Desktop.
Save pldubouilh/9f98cf2b5a4e0ba5676cab111ec3728b to your computer and use it in GitHub Desktop.
system wide accessible pinned eBPF maps
/**
* some musings around eBPF maps, for defining || reusing per-cpu maps
*
* maps defined here are accessible system-wide as they are defining or using a pin
*
* useful monitoring cmds:
* sudo bpftool map dump pinned /sys/fs/bpf/h2o_map
* sudo bpftool map show
*/
#include <stdio.h>
#include <sys/sdt.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <linux/unistd.h>
#include <linux/bpf.h>
struct keyType {
__u64 ipa;
__u64 ipb;
__u32 porta;
__u32 portb;
};
char name[] = "h2o_map";
char path[] = "/sys/fs/bpf/h2o_map";
int fd;
int id;
int bpf_create_map() {
union bpf_attr attr;
struct keyType *key;
memset(&attr, '\0', sizeof(attr));
attr.map_type = BPF_MAP_TYPE_PERCPU_HASH;
attr.key_size = sizeof(key);
attr.value_size = sizeof(char);
attr.max_entries = 50;
memcpy(attr.map_name, &name[0], strlen(name));
return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}
int bpf_pin_map() {
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.pathname = (__u64) (unsigned long)(void *)&path[0];
attr.bpf_fd = fd;
return syscall(__NR_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
}
void bpf_read_map_at_path() {
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.pathname = (__u64) (unsigned long)&path[0];
fd = syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
}
int bpf_map_lookup_elem(const void *key, void *value) {
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_fd = fd;
attr.key = (__u64) (unsigned long)key;
attr.value = (__u64) (unsigned long)value;
return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
int bpf_map_update_elem(const void *key, void *value)
{
union bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.map_fd = fd;
attr.key = (__u64) (unsigned long)key;
attr.value = (__u64) (unsigned long)value;
attr.flags = BPF_ANY;
return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}
void init() {
// leave if we have a fd
if (fd > 0) return;
printf("trying to read map at %s... ", path);
bpf_read_map_at_path();
printf("%s\r\n", strerror(errno));
errno = 0;
// we have a FD from an existing map
if (fd > 0) return;
// cant read, try create a map
printf("%s\r\ntrying to create now... ", strerror(errno));
fd = bpf_create_map();
printf("%s\r\n", strerror(errno));
errno = 0;
// cant create :(
if (fd == -1) return;
// now pinning map for system wide access
printf("trying to pin to %s... ", path);
bpf_pin_map();
printf("%s\r\n", strerror(errno));
errno = 0;
}
#define CPUS 4
#define bump() do{ for(int i=0; i<CPUS; i++) vals[i] += 1;} while(0)
#define reset() do{ memset(&vals[0], 0, sizeof(vals)); } while(0)
int main(int argc, char **argv) {
fd = 0;
struct keyType key;
key.ipa = 127001;
key.ipb = 127002;
key.porta = 3022;
key.portb = 3080;
// values are contained in a __u64, CPU wide array.
// lookup will be performed on all CPUS (same for updates)
__u64 vals[CPUS] = {10, 11, 12, 13};
init();
while(1) {
bump();
bpf_map_update_elem(&key, &vals[0]);
printf("wrote key: {%lld:%d, %lld:%d}, val: {%d, %d, %d, %d}\r\n", key.ipa, key.porta, key.ipb, key.portb, vals[0], vals[1], vals[2], vals[3]);
sleep(1);
reset();
bpf_map_lookup_elem(&key, &vals);
printf("read key: {%lld:%d, %lld:%d}, val: {%d, %d, %d, %d}\r\n", key.ipa, key.porta, key.ipb, key.portb, vals[0], vals[1], vals[2], vals[3]);
sleep(1);
printf("~~~~~~~~~~~~~\r\n");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment