The BPF_ST_ATOMIC_REG macro token-pasted the legacy rte_atomicNN_*() API names. It also stacked three casts on the destination pointer and reached a 'return 0' out of the macro into the caller's control flow.
Replace it with two small static-inline helpers, bpf_atomic32() and bpf_atomic64(), that dispatch on ins->imm internally and use the C11 atomic intrinsics directly. The destination is cast once, to a properly __rte_atomic-qualified pointer. The helpers return a status and the dispatch loop owns the early exit. Use memory order seq_cst to preserve the previous behavior of rte_atomicNN_add() / rte_atomicNN_exchange() and matches the Linux kernel BPF interpreter for these opcodes. Signed-off-by: Stephen Hemminger <[email protected]> --- lib/bpf/bpf_exec.c | 91 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/lib/bpf/bpf_exec.c b/lib/bpf/bpf_exec.c index 18013753b1..b8116db191 100644 --- a/lib/bpf/bpf_exec.c +++ b/lib/bpf/bpf_exec.c @@ -64,28 +64,6 @@ (*(type *)(uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off) = \ (type)(reg)[(ins)->src_reg]) -#define BPF_ST_ATOMIC_REG(reg, ins, tp) do { \ - switch (ins->imm) { \ - case BPF_ATOMIC_ADD: \ - rte_atomic##tp##_add((rte_atomic##tp##_t *) \ - (uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off), \ - (reg)[(ins)->src_reg]); \ - break; \ - case BPF_ATOMIC_XCHG: \ - (reg)[(ins)->src_reg] = rte_atomic##tp##_exchange((uint##tp##_t *) \ - (uintptr_t)((reg)[(ins)->dst_reg] + (ins)->off), \ - (reg)[(ins)->src_reg]); \ - break; \ - default: \ - /* this should be caught by validator and never reach here */ \ - RTE_BPF_LOG_LINE(ERR, \ - "%s(%p): unsupported atomic operation at pc: %#zx;", \ - __func__, bpf, \ - (uintptr_t)(ins) - (uintptr_t)(bpf)->prm.ins); \ - return 0; \ - } \ -} while (0) - /* BPF_LD | BPF_ABS/BPF_IND */ #define NOP(x) (x) @@ -105,6 +83,69 @@ reg[EBPF_REG_0] = op(p[0]); \ } while (0) +/* + * Atomic ops on the BPF target memory. + * + * BPF atomic instructions encode the destination as base register + + * signed offset, with the value to combine taken from src_reg. + * + * Memory order: seq_cst preserves the previous behavior of + * rte_atomicNN_add() / rte_atomicNN_exchange() and matches what the + * Linux kernel BPF interpreter does for these opcodes. + * + * Returns 0 on unsupported sub-op (validator should have rejected it), + * 1 otherwise. + */ +static inline int +bpf_atomic32(const struct rte_bpf *bpf, uint64_t reg[EBPF_REG_NUM], + const struct ebpf_insn *ins) +{ + /* need to casts to make bpf memory suitable for C11 atomic */ + uint32_t __rte_atomic *dst + = (uint32_t __rte_atomic *)(uintptr_t)(reg[ins->dst_reg] + ins->off); + uint32_t val = (uint32_t)reg[ins->src_reg]; + + switch (ins->imm) { + case BPF_ATOMIC_ADD: + rte_atomic_fetch_add_explicit(dst, val, rte_memory_order_seq_cst); + return 1; + case BPF_ATOMIC_XCHG: + reg[ins->src_reg] = rte_atomic_exchange_explicit(dst, val, + rte_memory_order_seq_cst); + return 1; + default: + RTE_BPF_LOG_LINE(ERR, + "%s(%p): unsupported atomic operation at pc: %#zx;", + __func__, bpf, + (uintptr_t)ins - (uintptr_t)bpf->prm.ins); + return 0; + } +} + +static inline int +bpf_atomic64(const struct rte_bpf *bpf, uint64_t reg[EBPF_REG_NUM], + const struct ebpf_insn *ins) +{ + uint64_t __rte_atomic *dst + = (uint64_t __rte_atomic *)(uintptr_t) (reg[ins->dst_reg] + ins->off); + uint64_t val = reg[ins->src_reg]; + + switch (ins->imm) { + case BPF_ATOMIC_ADD: + rte_atomic_fetch_add_explicit(dst, val, rte_memory_order_seq_cst); + return 1; + case BPF_ATOMIC_XCHG: + reg[ins->src_reg] = rte_atomic_exchange_explicit(dst, val, + rte_memory_order_seq_cst); + return 1; + default: + RTE_BPF_LOG_LINE(ERR, + "%s(%p): unsupported atomic operation at pc: %#zx;", + __func__, bpf, + (uintptr_t)ins - (uintptr_t)bpf->prm.ins); + return 0; + } +} static inline void bpf_alu_be(uint64_t reg[EBPF_REG_NUM], const struct ebpf_insn *ins) @@ -392,10 +433,12 @@ bpf_exec(const struct rte_bpf *bpf, uint64_t reg[EBPF_REG_NUM]) break; /* atomic instructions */ case (BPF_STX | EBPF_ATOMIC | BPF_W): - BPF_ST_ATOMIC_REG(reg, ins, 32); + if (bpf_atomic32(bpf, reg, ins) == 0) + return 0; break; case (BPF_STX | EBPF_ATOMIC | EBPF_DW): - BPF_ST_ATOMIC_REG(reg, ins, 64); + if (bpf_atomic64(bpf, reg, ins) == 0) + return 0; break; /* jump instructions */ case (BPF_JMP | BPF_JA): -- 2.53.0

