diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h index 01bdc68..c6b417f 100644 --- a/progs/include/bpf_helpers.h +++ b/progs/include/bpf_helpers.h @@ -11,11 +11,63 @@ * Helper functions called from eBPF programs written in C. These are * implemented in the kernel sources. */ + /* generic functions */ -static void* (*bpf_map_lookup_elem)(void* map, void* key) = (void*) BPF_FUNC_map_lookup_elem; -static int (*bpf_map_update_elem)(void* map, void* key, void* value, - unsigned long long flags) = (void*) BPF_FUNC_map_update_elem; -static int (*bpf_map_delete_elem)(void* map, void* key) = (void*) BPF_FUNC_map_delete_elem; + +/* + * Type-unsafe bpf map functions - avoid if possible. + * + * Using these it is possible to pass in keys/values of the wrong type/size, + * or, for 'unsafe_bpf_map_lookup_elem' receive into a pointer to the wrong type. + * You will not get a compile time failure, and for certain types of errors you + * might not even get a failure from the kernel's ebpf verifier during program load, + * instead stuff might just not work right at runtime. + * + * Instead please use: + * DEFINE_BPF_MAP(foo_map, TYPE, KeyType, ValueType, num_entries) + * where TYPE can be something like HASH or ARRAY, and num_entries is an integer. + * + * This defines the map (hence this should not be used in a header file included + * from multiple locations) and provides type safe accessors: + * ValueType * bpf_foo_map_lookup_elem(KeyType *) + * int bpf_foo_map_update_elem(KeyType *, ValueType *, flags) + * int bpf_foo_map_delete_elem(KeyType *) + * + * This will make sure that if you change the type of a map you'll get compile + * errors at any spots you forget to update with the new type. + */ +static void* (*unsafe_bpf_map_lookup_elem)(void* map, void* key) = (void*)BPF_FUNC_map_lookup_elem; +static int (*unsafe_bpf_map_update_elem)(void* map, void* key, void* value, + unsigned long long flags) = (void*) + BPF_FUNC_map_update_elem; +static int (*unsafe_bpf_map_delete_elem)(void* map, void* key) = (void*)BPF_FUNC_map_delete_elem; + +/* type safe macro to declare a map and related accessor functions */ +#define DEFINE_BPF_MAP_NO_ACCESSORS(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ + struct bpf_map_def SEC("maps") the_map = { \ + .type = BPF_MAP_TYPE_##TYPE, \ + .key_size = sizeof(TypeOfKey), \ + .value_size = sizeof(TypeOfValue), \ + .max_entries = (num_entries), \ + }; + +#define DEFINE_BPF_MAP(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ + DEFINE_BPF_MAP_NO_ACCESSORS(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \ + \ + static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem( \ + TypeOfKey* k) { \ + return unsafe_bpf_map_lookup_elem(&the_map, k); \ + }; \ + \ + static inline __always_inline __unused int bpf_##the_map##_update_elem( \ + TypeOfKey* k, TypeOfValue* v, unsigned long long flags) { \ + return unsafe_bpf_map_update_elem(&the_map, k, v, flags); \ + }; \ + \ + static inline __always_inline __unused int bpf_##the_map##_delete_elem(TypeOfKey* k) { \ + return unsafe_bpf_map_delete_elem(&the_map, k); \ + }; + static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read; static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str; static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns;