-
Notifications
You must be signed in to change notification settings - Fork 354
Description
Two previous issues (#947 and #588) have explained that it is possible to use intrinsics such as atomic_xadd_relaxed() to generate BPF atomic instructions.
However, it does not seem possible to do a BPF atomic "add and fetch" this way.
Suppose seq_num is a *mut u32. The following compiles ok.
atomic_xadd_relaxed(seq_num, 1);
But this fails to compile.
let prev_value = atomic_xadd_relaxed(seq_num, 1);
info!(&cxt, "Prev value {}", prev_value);
with ERROR llvm: :0:0: in function ebpf_downlink i32 (ptr): Invalid usage of the XADD return value.
From inspecting the bytecode with bpftool, the issue is that the BPF_FETCH modifier (defined at https://www.rfc-editor.org/rfc/rfc9669.html#name-atomic-operations) is not being set, so it's not surprising that this code that tries to use a return value doesn't work.
From https://www.kernel.org/doc/html/v5.17/bpf/instruction-set.html#atomic-operations, when BPF_FETCH is set, "these operations also overwrite src_reg with the value that was in memory before it was modified".
If I patch the eBPF bytecode, I can see the above in action.
Instruction as shown by bpftool without BPF_FETCH:
(c3) lock *(u32 *)(r0 +0) += r1
Instruction in patched bytecode as shown by bpftool with BPF_FETCH:
(c3) r1 = atomic_fetch_add((u32 *)(r0 +0), r1)
So: how do I generate an atomic_fetch_add() BPF instruction without patching the bytecode?
If there is no way to do that, would it be possible to have a fix/enhancement?