ebpf_user_macros/
lib.rs

1use syn::{Data, DeriveInput, parse_macro_input};
2
3#[proc_macro_derive(BpfApp, attributes(license, hashmap, array_percpu, ringbuf, prog))]
4pub fn derive_bpf_app(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
5    let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);
6
7    struct UserTokens<T> {
8        map_cnt: T,
9        prog_cnt: T,
10        new_field: T,
11        map_step: T,
12        prog_step: T,
13    }
14
15    let ut = UserTokens {
16        map_cnt: quote::quote! {},
17        prog_cnt: quote::quote! {},
18        new_field: quote::quote! {},
19        map_step: quote::quote! {},
20        prog_step: quote::quote! {},
21    };
22
23    let ut = match data {
24        Data::Struct(data) => data.fields.into_iter().fold(ut, |ut, field| {
25            let UserTokens {
26                map_cnt,
27                prog_cnt,
28                new_field,
29                map_step,
30                prog_step,
31            } = ut;
32            let val = field.ident.unwrap();
33            let val_str = format!("{}\0", val);
34            let ty = field.ty;
35            UserTokens {
36                map_cnt: quote::quote! { #map_cnt + <#ty as ebpf_user::kind::AppItem>::MAP },
37                prog_cnt: quote::quote! { #prog_cnt + <#ty as ebpf_user::kind::AppItem>::PROG },
38                new_field: quote::quote! { #new_field #val: <#ty>::named(#val_str), },
39                map_step: quote::quote! {
40                    #map_step
41                    if let ebpf_user::kind::AppItemKindMut::Map(v) = self.#val.kind_mut() {
42                        if counter == index {
43                            return Some(v);
44                        } else {
45                            counter += 1;
46                        }
47                    }
48                },
49                prog_step: quote::quote! {
50                    #prog_step
51                    if let ebpf_user::kind::AppItemKindMut::Prog(v) = self.#val.kind_mut() {
52                        if counter == index {
53                            return Some(v);
54                        } else {
55                            counter += 1;
56                        }
57                    }
58                },
59            }
60        }),
61        _ => unimplemented!(),
62    };
63
64    let UserTokens {
65        map_cnt,
66        prog_cnt,
67        new_field,
68        map_step,
69        prog_step,
70    } = ut;
71
72    proc_macro::TokenStream::from(quote::quote! {
73        impl ebpf_user::BpfApp for #ident {
74            const MAP_CNT: usize = 0 #map_cnt;
75            const PROG_CNT: usize = 0 #prog_cnt;
76
77            fn instance() -> Self {
78                use ebpf_user::kind::AppItem;
79
80                #ident {
81                    #new_field
82                }
83            }
84
85            fn as_mut_map(&mut self, index: usize) -> Option<&mut ebpf_user::MapRef> {
86                use ebpf_user::kind::AppItem;
87
88                let mut counter = 0;
89                #map_step
90                let _ = counter;
91                None
92            }
93
94            fn as_mut_prog(&mut self, index: usize) -> Option<&mut ebpf_user::ProgRef> {
95                use ebpf_user::kind::AppItem;
96
97                let mut counter = 0;
98                #prog_step
99                let _ = counter;
100                None
101            }
102        }
103    })
104}