-
-
Save pldubouilh/9f98cf2b5a4e0ba5676cab111ec3728b to your computer and use it in GitHub Desktop.
system wide accessible pinned eBPF maps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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