Commit 1a0a383
committed
[BPF] Support wrapping BPF map structs into nested, single field structs
In Aya/Rust, BPF map definitions are nested in two wrapper types:
* Structs representing the given map type (`HashMap`, `RingBuf` etc.),
which provide methods associated with that type. This way, we can
define methods like `HashMap::get` or `RingBuf::reserve`, making the
interaction with maps more "rusty".
* `UnsafeCell`, which lets the Rust compiler know that such type is
thread safe, can be defined as a static (global) variable and can be
safely mutated. Linux kernel already guarantees the thread safety of
map operations.
The type hierarchy of such nested map definitions usually looks like:
```rust
pub struct HashMap<K, V, const M: usize, const F: usize = 0>(
HashMapCell<K, V, M, F>
);
pub type HashMapCell<K, V, const M: usize, const F: usize = 0> =
UnsafeCell<HashMapDef<K, V, M, F>>;
const BPF_MAP_TYPE_HASH: usize = 1;
pub struct HashMapDef<K, V, const M: usize, const F: usize = 0> {
r#type: *const [i32; BPF_MAP_TYPE_HASH],
key: *const K,
value: *const V,
max_entries: *const [i32; M],
map_flags: *const [i32; F],
}
```
The map type is then used in a global variable, defined in the BPF
program code:
```rust
#[link_section = ".maps"]
static HASH_MAP: HashMap<u32, u32, 10> = HashMap::new();
```
Which is an equivalent of the following BPF map definition in C:
```c
#define BPF_MAP_TYPE_HASH 1
struct {
int (*type)[BPF_MAP_TYPE_HASH];
typeof(int) *key;
typeof(int) *value;
int (*max_entries)[10];
} map_1 __attribute__((section(".maps")));
```
Visiting such map requires visiting the following fields, in order to
get to the actual map definition (`HashMapDef`):
```
HASH_MAP -> __0 -> value
```
Before this change, the BPF backend was visiting only the fields of the
outer struct, without traversing them deeper. That caused problems with
maps using custom structs as keys and/or values, like:
```rust
// Define custom structs for key and values.
pub struct MyKey(u32);
pub struct MyValue(u32);
#[link_section = ".maps"]
#[export_name = "HASH_MAP"]
pub static HASH_MAP: HashMap<MyKey, MyValue, 10> = HashMap::new();
```
Because the `MyKey` and `MyValue` types didn't end up being actually
visited, and therefore ended up as a forward declaration in BTF:
```
#30: <FWD> 'MyKey' kind:struct
#31: <FWD> 'MyValue' kind:struct
```
Fix that by looking in the map definitions recursively, if they turn out
to be single-field wrappers. The correct BTF for these types, after the
fix:
```
#6: <STRUCT> 'MyKey' sz:4 n:1
#00 '__0' off:0 --> [7]
#7: <INT> 'u32' bits:32 off:0
#8: <PTR> --> [9]
#9: <STRUCT> 'MyValue' sz:4 n:1
#00 '__0' off:0 --> [7]
```
Fixes: #1433611 parent 891a2c3 commit 1a0a383
File tree
2 files changed
+622
-2
lines changed- llvm
- lib/Target/BPF
- test/CodeGen/BPF/BTF
2 files changed
+622
-2
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| 27 | + | |
26 | 28 | | |
27 | 29 | | |
28 | 30 | | |
| |||
976 | 978 | | |
977 | 979 | | |
978 | 980 | | |
979 | | - | |
| 981 | + | |
980 | 982 | | |
981 | 983 | | |
982 | 984 | | |
983 | | - | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
984 | 998 | | |
985 | 999 | | |
986 | 1000 | | |
| |||
0 commit comments