1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Anton Protopopov
3*387f9dfdSAndroid Build Coastguard Worker #ifndef __MAPS_BPF_H
4*387f9dfdSAndroid Build Coastguard Worker #define __MAPS_BPF_H
5*387f9dfdSAndroid Build Coastguard Worker
6*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_helpers.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <asm-generic/errno.h>
8*387f9dfdSAndroid Build Coastguard Worker
9*387f9dfdSAndroid Build Coastguard Worker static __always_inline void *
bpf_map_lookup_or_try_init(void * map,const void * key,const void * init)10*387f9dfdSAndroid Build Coastguard Worker bpf_map_lookup_or_try_init(void *map, const void *key, const void *init)
11*387f9dfdSAndroid Build Coastguard Worker {
12*387f9dfdSAndroid Build Coastguard Worker void *val;
13*387f9dfdSAndroid Build Coastguard Worker /* bpf helper functions like bpf_map_update_elem() below normally return
14*387f9dfdSAndroid Build Coastguard Worker * long, but using int instead of long to store the result is a workaround
15*387f9dfdSAndroid Build Coastguard Worker * to avoid incorrectly evaluating err in cases where the following criteria
16*387f9dfdSAndroid Build Coastguard Worker * is met:
17*387f9dfdSAndroid Build Coastguard Worker * the architecture is 64-bit
18*387f9dfdSAndroid Build Coastguard Worker * the helper function return type is long
19*387f9dfdSAndroid Build Coastguard Worker * the helper function returns the value of a call to a bpf_map_ops func
20*387f9dfdSAndroid Build Coastguard Worker * the bpf_map_ops function return type is int
21*387f9dfdSAndroid Build Coastguard Worker * the compiler inlines the helper function
22*387f9dfdSAndroid Build Coastguard Worker * the compiler does not sign extend the result of the bpf_map_ops func
23*387f9dfdSAndroid Build Coastguard Worker *
24*387f9dfdSAndroid Build Coastguard Worker * if this criteria is met, at best an error can only be checked as zero or
25*387f9dfdSAndroid Build Coastguard Worker * non-zero. it will not be possible to check for a negative value or a
26*387f9dfdSAndroid Build Coastguard Worker * specific error value. this is because the sign bit would have been stuck
27*387f9dfdSAndroid Build Coastguard Worker * at the 32nd bit of a 64-bit long int.
28*387f9dfdSAndroid Build Coastguard Worker */
29*387f9dfdSAndroid Build Coastguard Worker int err;
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker val = bpf_map_lookup_elem(map, key);
32*387f9dfdSAndroid Build Coastguard Worker if (val)
33*387f9dfdSAndroid Build Coastguard Worker return val;
34*387f9dfdSAndroid Build Coastguard Worker
35*387f9dfdSAndroid Build Coastguard Worker err = bpf_map_update_elem(map, key, init, BPF_NOEXIST);
36*387f9dfdSAndroid Build Coastguard Worker if (err && err != -EEXIST)
37*387f9dfdSAndroid Build Coastguard Worker return 0;
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker return bpf_map_lookup_elem(map, key);
40*387f9dfdSAndroid Build Coastguard Worker }
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Worker #endif /* __MAPS_BPF_H */
43