bpf: define READ_ONCE and WRITE_ONCE
These are convenience macros which do
(const|volatile) cast for atomic operations.
I've run into a case where two 32-bit writes get optimized
by the compiler into a single 64-bit write, which then fails
verification. WRITE_ONCE() avoids that by virtue of the volatile annotation.
Technically I think the same thing could happen on read,
so add READ_ONCE too.
Test: N/A
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Iade089aab3522916bd7b431d4064f89a21bc78b0
diff --git a/bpf/headers/include/bpf_helpers.h b/bpf/headers/include/bpf_helpers.h
index 67de633..6a0e5a8 100644
--- a/bpf/headers/include/bpf_helpers.h
+++ b/bpf/headers/include/bpf_helpers.h
@@ -419,6 +419,22 @@
DEFINE_BPF_MAP_UGM(the_map, TYPE, KeyType, ValueType, num_entries, \
DEFAULT_BPF_MAP_UID, gid, 0660)
+// idea from Linux include/linux/compiler_types.h (eBPF is always a 64-bit arch)
+#define NATIVE_WORD(t) ((sizeof(t) == 1) || (sizeof(t) == 2) || (sizeof(t) == 4) || (sizeof(t) == 8))
+
+// simplified from Linux include/asm-generic/rwonce.h
+#define READ_ONCE(x) \
+ ({ \
+ _Static_assert(NATIVE_WORD(x), "READ_ONCE requires a native word size"); \
+ (*(const volatile typeof(x) *)&(x)) \
+ })
+
+#define WRITE_ONCE(x, value) \
+ do { \
+ _Static_assert(NATIVE_WORD(x), "WRITE_ONCE requires a native word size"); \
+ *(volatile typeof(x) *)&(x) = (value); \
+ } while (0)
+
// LLVM eBPF builtins: they directly generate BPF_LD_ABS/BPF_LD_IND (skb may be ignored?)
unsigned long long load_byte(void* skb, unsigned long long off) asm("llvm.bpf.load.byte");
unsigned long long load_half(void* skb, unsigned long long off) asm("llvm.bpf.load.half");