expand.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. use proc_macro2::TokenStream;
  2. use quote::quote;
  3. use syn::{
  4. parse::{Parse, ParseStream},
  5. punctuated::{Pair, Punctuated},
  6. token::Eq,
  7. Error, Ident, ItemFn, ItemStatic, LitStr, Result, Token,
  8. };
  9. pub struct NameValue {
  10. name: Ident,
  11. _eq: Eq,
  12. value: LitStr,
  13. }
  14. pub struct Args {
  15. args: Vec<NameValue>,
  16. }
  17. impl Parse for Args {
  18. fn parse(input: ParseStream) -> Result<Args> {
  19. let args = Punctuated::<NameValue, Token![,]>::parse_terminated_with(input, |input| {
  20. Ok(NameValue {
  21. name: input.parse()?,
  22. _eq: input.parse()?,
  23. value: input.parse()?,
  24. })
  25. })?
  26. .into_pairs()
  27. .map(|pair| match pair {
  28. Pair::Punctuated(name_val, _) => name_val,
  29. Pair::End(name_val) => name_val,
  30. })
  31. .collect();
  32. Ok(Args { args })
  33. }
  34. }
  35. pub struct SockAddrArgs {
  36. pub(crate) attach_type: Ident,
  37. pub(crate) args: Args,
  38. }
  39. impl Parse for SockAddrArgs {
  40. fn parse(input: ParseStream) -> Result<SockAddrArgs> {
  41. let attach_type: Ident = input.parse()?;
  42. match attach_type.to_string().as_str() {
  43. "connect4" | "connect6" | "bind4" | "bind6" | "getpeername4" | "getpeername6"
  44. | "getsockname4" | "getsockname6" | "sendmsg4" | "sendmsg6" | "recvmsg4"
  45. | "recvmsg6" => (),
  46. _ => return Err(input.error("invalid attach type")),
  47. }
  48. let args = if input.parse::<Token![,]>().is_ok() {
  49. Args::parse(input)?
  50. } else {
  51. Args { args: vec![] }
  52. };
  53. Ok(SockAddrArgs { attach_type, args })
  54. }
  55. }
  56. pub struct SockoptArgs {
  57. pub(crate) attach_type: Ident,
  58. pub(crate) args: Args,
  59. }
  60. impl Parse for SockoptArgs {
  61. fn parse(input: ParseStream) -> Result<SockoptArgs> {
  62. let attach_type: Ident = input.parse()?;
  63. match attach_type.to_string().as_str() {
  64. "getsockopt" | "setsockopt" => (),
  65. _ => return Err(input.error("invalid attach type")),
  66. }
  67. let args = if input.parse::<Token![,]>().is_ok() {
  68. Args::parse(input)?
  69. } else {
  70. Args { args: vec![] }
  71. };
  72. Ok(SockoptArgs { attach_type, args })
  73. }
  74. }
  75. pub struct Map {
  76. item: ItemStatic,
  77. name: String,
  78. }
  79. impl Map {
  80. pub fn from_syn(mut args: Args, item: ItemStatic) -> Result<Map> {
  81. let name = name_arg(&mut args)?.unwrap_or_else(|| item.ident.to_string());
  82. Ok(Map { item, name })
  83. }
  84. pub fn expand(&self) -> Result<TokenStream> {
  85. let section_name = "maps";
  86. let name = &self.name;
  87. let item = &self.item;
  88. Ok(quote! {
  89. #[link_section = #section_name]
  90. #[export_name = #name]
  91. #item
  92. })
  93. }
  94. }
  95. pub struct Probe {
  96. kind: ProbeKind,
  97. item: ItemFn,
  98. name: String,
  99. }
  100. impl Probe {
  101. pub fn from_syn(kind: ProbeKind, mut args: Args, item: ItemFn) -> Result<Probe> {
  102. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  103. Ok(Probe { kind, item, name })
  104. }
  105. pub fn expand(&self) -> Result<TokenStream> {
  106. let section_name = format!("{}/{}", self.kind, self.name);
  107. let fn_vis = &self.item.vis;
  108. let fn_name = &self.item.sig.ident;
  109. let item = &self.item;
  110. Ok(quote! {
  111. #[no_mangle]
  112. #[link_section = #section_name]
  113. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  114. let _ = #fn_name(::aya_bpf::programs::ProbeContext::new(ctx));
  115. return 0;
  116. #item
  117. }
  118. })
  119. }
  120. }
  121. pub struct SockOps {
  122. item: ItemFn,
  123. name: Option<String>,
  124. }
  125. impl SockOps {
  126. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SockOps> {
  127. let name = name_arg(&mut args)?;
  128. Ok(SockOps { item, name })
  129. }
  130. pub fn expand(&self) -> Result<TokenStream> {
  131. let section_name: std::borrow::Cow<'_, _> = if let Some(name) = &self.name {
  132. format!("sockops/{name}").into()
  133. } else {
  134. "sockops".into()
  135. };
  136. let fn_vis = &self.item.vis;
  137. let fn_name = &self.item.sig.ident;
  138. let item = &self.item;
  139. Ok(quote! {
  140. #[no_mangle]
  141. #[link_section = #section_name]
  142. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock_ops) -> u32 {
  143. return #fn_name(::aya_bpf::programs::SockOpsContext::new(ctx));
  144. #item
  145. }
  146. })
  147. }
  148. }
  149. pub struct SkMsg {
  150. item: ItemFn,
  151. name: String,
  152. }
  153. impl SkMsg {
  154. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SkMsg> {
  155. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  156. Ok(SkMsg { item, name })
  157. }
  158. pub fn expand(&self) -> Result<TokenStream> {
  159. let section_name = format!("sk_msg/{}", self.name);
  160. let fn_vis = &self.item.vis;
  161. let fn_name = &self.item.sig.ident;
  162. let item = &self.item;
  163. Ok(quote! {
  164. #[no_mangle]
  165. #[link_section = #section_name]
  166. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::sk_msg_md) -> u32 {
  167. return #fn_name(::aya_bpf::programs::SkMsgContext::new(ctx));
  168. #item
  169. }
  170. })
  171. }
  172. }
  173. pub struct Xdp {
  174. item: ItemFn,
  175. name: Option<String>,
  176. frags: bool,
  177. }
  178. impl Xdp {
  179. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<Xdp> {
  180. let name = pop_arg(&mut args, "name");
  181. let mut frags = false;
  182. if let Some(s) = pop_arg(&mut args, "frags") {
  183. if let Ok(m) = s.parse() {
  184. frags = m
  185. } else {
  186. return Err(Error::new_spanned(
  187. s,
  188. "invalid value. should be 'true' or 'false'",
  189. ));
  190. }
  191. }
  192. err_on_unknown_args(&args)?;
  193. Ok(Xdp { item, name, frags })
  194. }
  195. pub fn expand(&self) -> Result<TokenStream> {
  196. let section_prefix = if self.frags { "xdp.frags" } else { "xdp" };
  197. let section_name = if let Some(name) = &self.name {
  198. format!("{section_prefix}/{name}")
  199. } else {
  200. section_prefix.to_string()
  201. };
  202. let fn_vis = &self.item.vis;
  203. let fn_name = &self.item.sig.ident;
  204. let item = &self.item;
  205. Ok(quote! {
  206. #[no_mangle]
  207. #[link_section = #section_name]
  208. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 {
  209. return #fn_name(::aya_bpf::programs::XdpContext::new(ctx));
  210. #item
  211. }
  212. })
  213. }
  214. }
  215. pub struct SchedClassifier {
  216. item: ItemFn,
  217. name: Option<String>,
  218. }
  219. impl SchedClassifier {
  220. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SchedClassifier> {
  221. let name = name_arg(&mut args)?;
  222. Ok(SchedClassifier { item, name })
  223. }
  224. pub fn expand(&self) -> Result<TokenStream> {
  225. let section_name: std::borrow::Cow<'_, _> = if let Some(name) = &self.name {
  226. format!("classifier/{name}").into()
  227. } else {
  228. "classifier".into()
  229. };
  230. let fn_vis = &self.item.vis;
  231. let fn_name = &self.item.sig.ident;
  232. let item = &self.item;
  233. Ok(quote! {
  234. #[no_mangle]
  235. #[link_section = #section_name]
  236. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i32 {
  237. return #fn_name(::aya_bpf::programs::TcContext::new(ctx));
  238. #item
  239. }
  240. })
  241. }
  242. }
  243. pub struct CgroupSysctl {
  244. item: ItemFn,
  245. name: Option<String>,
  246. }
  247. impl CgroupSysctl {
  248. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<CgroupSysctl> {
  249. let name = name_arg(&mut args)?;
  250. Ok(CgroupSysctl { item, name })
  251. }
  252. pub fn expand(&self) -> Result<TokenStream> {
  253. let section_name = if let Some(name) = &self.name {
  254. format!("cgroup/sysctl/{name}")
  255. } else {
  256. ("cgroup/sysctl").to_owned()
  257. };
  258. let fn_vis = &self.item.vis;
  259. let fn_name = &self.item.sig.ident;
  260. let item = &self.item;
  261. Ok(quote! {
  262. #[no_mangle]
  263. #[link_section = #section_name]
  264. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sysctl) -> i32 {
  265. return #fn_name(::aya_bpf::programs::SysctlContext::new(ctx));
  266. #item
  267. }
  268. })
  269. }
  270. }
  271. pub struct CgroupSockopt {
  272. item: ItemFn,
  273. attach_type: String,
  274. name: Option<String>,
  275. }
  276. impl CgroupSockopt {
  277. pub fn from_syn(mut args: Args, item: ItemFn, attach_type: String) -> Result<CgroupSockopt> {
  278. let name = pop_arg(&mut args, "name");
  279. err_on_unknown_args(&args)?;
  280. Ok(CgroupSockopt {
  281. item,
  282. attach_type,
  283. name,
  284. })
  285. }
  286. pub fn expand(&self) -> Result<TokenStream> {
  287. let section_name = if let Some(name) = &self.name {
  288. format!("cgroup/{}/{}", self.attach_type, name)
  289. } else {
  290. format!("cgroup/{}", self.attach_type)
  291. };
  292. let fn_vis = &self.item.vis;
  293. let fn_name = &self.item.sig.ident;
  294. let item = &self.item;
  295. Ok(quote! {
  296. #[no_mangle]
  297. #[link_section = #section_name]
  298. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sockopt) -> i32 {
  299. return #fn_name(::aya_bpf::programs::SockoptContext::new(ctx));
  300. #item
  301. }
  302. })
  303. }
  304. }
  305. pub struct CgroupSkb {
  306. item: ItemFn,
  307. expected_attach_type: Option<String>,
  308. name: Option<String>,
  309. }
  310. impl CgroupSkb {
  311. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<CgroupSkb> {
  312. let name = pop_arg(&mut args, "name");
  313. let expected_attach_type = pop_arg(&mut args, "attach");
  314. err_on_unknown_args(&args)?;
  315. Ok(CgroupSkb {
  316. item,
  317. expected_attach_type,
  318. name,
  319. })
  320. }
  321. pub fn expand(&self) -> Result<TokenStream> {
  322. let section_name = if let Some(attach) = &self.expected_attach_type {
  323. if let Some(name) = &self.name {
  324. format!("cgroup_skb/{attach}/{name}")
  325. } else {
  326. format!("cgroup_skb/{attach}")
  327. }
  328. } else if let Some(name) = &self.name {
  329. format!("cgroup/skb/{name}")
  330. } else {
  331. ("cgroup/skb").to_owned()
  332. };
  333. let fn_vis = &self.item.vis;
  334. let fn_name = &self.item.sig.ident;
  335. let item = &self.item;
  336. Ok(quote! {
  337. #[no_mangle]
  338. #[link_section = #section_name]
  339. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i32 {
  340. return #fn_name(::aya_bpf::programs::SkBuffContext::new(ctx));
  341. #item
  342. }
  343. })
  344. }
  345. }
  346. pub struct CgroupSockAddr {
  347. item: ItemFn,
  348. attach_type: String,
  349. name: Option<String>,
  350. }
  351. impl CgroupSockAddr {
  352. pub fn from_syn(mut args: Args, item: ItemFn, attach_type: String) -> Result<CgroupSockAddr> {
  353. let name = pop_arg(&mut args, "name");
  354. err_on_unknown_args(&args)?;
  355. Ok(CgroupSockAddr {
  356. item,
  357. attach_type,
  358. name,
  359. })
  360. }
  361. pub fn expand(&self) -> Result<TokenStream> {
  362. let section_name = if let Some(name) = &self.name {
  363. format!("cgroup/{}/{}", self.attach_type, name)
  364. } else {
  365. format!("cgroup/{}", self.attach_type)
  366. };
  367. let fn_vis = &self.item.vis;
  368. let fn_name = &self.item.sig.ident;
  369. let item = &self.item;
  370. Ok(quote! {
  371. #[no_mangle]
  372. #[link_section = #section_name]
  373. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock_addr) -> i32 {
  374. return #fn_name(::aya_bpf::programs::SockAddrContext::new(ctx));
  375. #item
  376. }
  377. })
  378. }
  379. }
  380. pub struct CgroupSock {
  381. item: ItemFn,
  382. attach_type: Option<String>,
  383. name: Option<String>,
  384. }
  385. impl CgroupSock {
  386. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<CgroupSock> {
  387. let name = pop_arg(&mut args, "name");
  388. let attach_type = pop_arg(&mut args, "attach");
  389. err_on_unknown_args(&args)?;
  390. Ok(CgroupSock {
  391. item,
  392. attach_type,
  393. name,
  394. })
  395. }
  396. pub fn expand(&self) -> Result<TokenStream> {
  397. let section_name: std::borrow::Cow<'_, _> = if let Some(name) = &self.name {
  398. if let Some(attach_type) = &self.attach_type {
  399. format!("cgroup/{attach_type}/{name}").into()
  400. } else {
  401. format!("cgroup/sock/{name}").into()
  402. }
  403. } else if let Some(attach_type) = &self.attach_type {
  404. format!("cgroup/{attach_type}").into()
  405. } else {
  406. "cgroup/sock".into()
  407. };
  408. let fn_vis = &self.item.vis;
  409. let fn_name = &self.item.sig.ident;
  410. let item = &self.item;
  411. Ok(quote! {
  412. #[no_mangle]
  413. #[link_section = #section_name]
  414. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock) -> i32 {
  415. return #fn_name(::aya_bpf::programs::SockContext::new(ctx));
  416. #item
  417. }
  418. })
  419. }
  420. }
  421. fn pop_arg(args: &mut Args, name: &str) -> Option<String> {
  422. match args.args.iter().position(|arg| arg.name == name) {
  423. Some(index) => Some(args.args.remove(index).value.value()),
  424. None => None,
  425. }
  426. }
  427. fn err_on_unknown_args(args: &Args) -> Result<()> {
  428. if let Some(arg) = args.args.get(0) {
  429. return Err(Error::new_spanned(&arg.name, "invalid argument"));
  430. }
  431. Ok(())
  432. }
  433. fn name_arg(args: &mut Args) -> Result<Option<String>> {
  434. let name = pop_arg(args, "name");
  435. err_on_unknown_args(args)?;
  436. Ok(name)
  437. }
  438. #[allow(clippy::enum_variant_names)]
  439. #[derive(Debug, Copy, Clone)]
  440. pub enum ProbeKind {
  441. KProbe,
  442. KRetProbe,
  443. UProbe,
  444. URetProbe,
  445. }
  446. impl std::fmt::Display for ProbeKind {
  447. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  448. use ProbeKind::*;
  449. match self {
  450. KProbe => write!(f, "kprobe"),
  451. KRetProbe => write!(f, "kretprobe"),
  452. UProbe => write!(f, "uprobe"),
  453. URetProbe => write!(f, "uretprobe"),
  454. }
  455. }
  456. }
  457. pub struct TracePoint {
  458. item: ItemFn,
  459. name: String,
  460. }
  461. impl TracePoint {
  462. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<TracePoint> {
  463. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  464. Ok(TracePoint { item, name })
  465. }
  466. pub fn expand(&self) -> Result<TokenStream> {
  467. let section_name = format!("tp/{}", self.name);
  468. let fn_vis = &self.item.vis;
  469. let fn_name = &self.item.sig.ident;
  470. let item = &self.item;
  471. Ok(quote! {
  472. #[no_mangle]
  473. #[link_section = #section_name]
  474. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  475. let _ = #fn_name(::aya_bpf::programs::TracePointContext::new(ctx));
  476. return 0;
  477. #item
  478. }
  479. })
  480. }
  481. }
  482. pub struct PerfEvent {
  483. item: ItemFn,
  484. name: String,
  485. }
  486. impl PerfEvent {
  487. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<PerfEvent> {
  488. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  489. Ok(PerfEvent { item, name })
  490. }
  491. pub fn expand(&self) -> Result<TokenStream> {
  492. let section_name = format!("perf_event/{}", self.name);
  493. let fn_vis = &self.item.vis;
  494. let fn_name = &self.item.sig.ident;
  495. let item = &self.item;
  496. Ok(quote! {
  497. #[no_mangle]
  498. #[link_section = #section_name]
  499. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  500. let _ = #fn_name(::aya_bpf::programs::PerfEventContext::new(ctx));
  501. return 0;
  502. #item
  503. }
  504. })
  505. }
  506. }
  507. pub struct RawTracePoint {
  508. item: ItemFn,
  509. name: String,
  510. }
  511. impl RawTracePoint {
  512. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<RawTracePoint> {
  513. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  514. Ok(RawTracePoint { item, name })
  515. }
  516. pub fn expand(&self) -> Result<TokenStream> {
  517. let section_name = format!("raw_tp/{}", self.name);
  518. let fn_vis = &self.item.vis;
  519. let fn_name = &self.item.sig.ident;
  520. let item = &self.item;
  521. Ok(quote! {
  522. #[no_mangle]
  523. #[link_section = #section_name]
  524. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  525. let _ = #fn_name(::aya_bpf::programs::RawTracePointContext::new(ctx));
  526. return 0;
  527. #item
  528. }
  529. })
  530. }
  531. }
  532. pub struct Lsm {
  533. item: ItemFn,
  534. name: Option<String>,
  535. sleepable: bool,
  536. }
  537. impl Lsm {
  538. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<Lsm> {
  539. let name = pop_arg(&mut args, "name");
  540. let mut sleepable = false;
  541. if let Some(s) = pop_arg(&mut args, "sleepable") {
  542. if let Ok(m) = s.parse() {
  543. sleepable = m
  544. } else {
  545. return Err(Error::new_spanned(
  546. s,
  547. "invalid value. should be 'true' or 'false'",
  548. ));
  549. }
  550. }
  551. err_on_unknown_args(&args)?;
  552. Ok(Lsm {
  553. item,
  554. name,
  555. sleepable,
  556. })
  557. }
  558. pub fn expand(&self) -> Result<TokenStream> {
  559. let section_prefix = if self.sleepable { "lsm.s" } else { "lsm" };
  560. let section_name = if let Some(name) = &self.name {
  561. format!("{section_prefix}/{name}")
  562. } else {
  563. section_prefix.to_string()
  564. };
  565. let fn_vis = &self.item.vis;
  566. let fn_name = &self.item.sig.ident;
  567. let item = &self.item;
  568. // LSM probes need to return an integer corresponding to the correct
  569. // policy decision. Therefore we do not simply default to a return value
  570. // of 0 as in other program types.
  571. Ok(quote! {
  572. #[no_mangle]
  573. #[link_section = #section_name]
  574. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
  575. return #fn_name(::aya_bpf::programs::LsmContext::new(ctx));
  576. #item
  577. }
  578. })
  579. }
  580. }
  581. pub struct BtfTracePoint {
  582. item: ItemFn,
  583. name: String,
  584. }
  585. impl BtfTracePoint {
  586. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<BtfTracePoint> {
  587. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  588. Ok(BtfTracePoint { item, name })
  589. }
  590. pub fn expand(&self) -> Result<TokenStream> {
  591. let section_name = format!("tp_btf/{}", self.name);
  592. let fn_vis = &self.item.vis;
  593. let fn_name = &self.item.sig.ident;
  594. let item = &self.item;
  595. Ok(quote! {
  596. #[no_mangle]
  597. #[link_section = #section_name]
  598. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
  599. let _ = #fn_name(::aya_bpf::programs::BtfTracePointContext::new(ctx));
  600. return 0;
  601. #item
  602. }
  603. })
  604. }
  605. }
  606. #[allow(clippy::enum_variant_names)]
  607. #[derive(Debug, Copy, Clone)]
  608. pub enum SkSkbKind {
  609. StreamVerdict,
  610. StreamParser,
  611. }
  612. impl std::fmt::Display for SkSkbKind {
  613. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  614. use SkSkbKind::*;
  615. match self {
  616. StreamVerdict => write!(f, "stream_verdict"),
  617. StreamParser => write!(f, "stream_parser"),
  618. }
  619. }
  620. }
  621. pub struct SkSkb {
  622. kind: SkSkbKind,
  623. item: ItemFn,
  624. name: Option<String>,
  625. }
  626. impl SkSkb {
  627. pub fn from_syn(kind: SkSkbKind, mut args: Args, item: ItemFn) -> Result<SkSkb> {
  628. let name = pop_arg(&mut args, "name");
  629. err_on_unknown_args(&args)?;
  630. Ok(SkSkb { item, kind, name })
  631. }
  632. pub fn expand(&self) -> Result<TokenStream> {
  633. let kind = &self.kind;
  634. let section_name = if let Some(name) = &self.name {
  635. format!("sk_skb/{kind}/{name}")
  636. } else {
  637. format!("sk_skb/{kind}")
  638. };
  639. let fn_vis = &self.item.vis;
  640. let fn_name = &self.item.sig.ident;
  641. let item = &self.item;
  642. Ok(quote! {
  643. #[no_mangle]
  644. #[link_section = #section_name]
  645. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> u32 {
  646. return #fn_name(::aya_bpf::programs::SkBuffContext::new(ctx));
  647. #item
  648. }
  649. })
  650. }
  651. }
  652. pub struct SocketFilter {
  653. item: ItemFn,
  654. name: Option<String>,
  655. }
  656. impl SocketFilter {
  657. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SocketFilter> {
  658. let name = name_arg(&mut args)?;
  659. err_on_unknown_args(&args)?;
  660. Ok(SocketFilter { item, name })
  661. }
  662. pub fn expand(&self) -> Result<TokenStream> {
  663. let section_name: std::borrow::Cow<'_, _> = if let Some(name) = &self.name {
  664. format!("socket/{name}").into()
  665. } else {
  666. "socket".into()
  667. };
  668. let fn_vis = &self.item.vis;
  669. let fn_name = &self.item.sig.ident;
  670. let item = &self.item;
  671. Ok(quote! {
  672. #[no_mangle]
  673. #[link_section = #section_name]
  674. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i64 {
  675. return #fn_name(::aya_bpf::programs::SkBuffContext::new(ctx));
  676. #item
  677. }
  678. })
  679. }
  680. }
  681. pub struct FEntry {
  682. item: ItemFn,
  683. name: String,
  684. }
  685. impl FEntry {
  686. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<FEntry> {
  687. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  688. Ok(FEntry { item, name })
  689. }
  690. pub fn expand(&self) -> Result<TokenStream> {
  691. let section_name = format!("fentry/{}", self.name);
  692. let fn_vis = &self.item.vis;
  693. let fn_name = &self.item.sig.ident;
  694. let item = &self.item;
  695. Ok(quote! {
  696. #[no_mangle]
  697. #[link_section = #section_name]
  698. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
  699. let _ = #fn_name(::aya_bpf::programs::FEntryContext::new(ctx));
  700. return 0;
  701. #item
  702. }
  703. })
  704. }
  705. }
  706. pub struct FExit {
  707. item: ItemFn,
  708. name: String,
  709. }
  710. impl FExit {
  711. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<FExit> {
  712. let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
  713. Ok(FExit { item, name })
  714. }
  715. pub fn expand(&self) -> Result<TokenStream> {
  716. let section_name = format!("fexit/{}", self.name);
  717. let fn_vis = &self.item.vis;
  718. let fn_name = &self.item.sig.ident;
  719. let item = &self.item;
  720. Ok(quote! {
  721. #[no_mangle]
  722. #[link_section = #section_name]
  723. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
  724. let _ = #fn_name(::aya_bpf::programs::FExitContext::new(ctx));
  725. return 0;
  726. #item
  727. }
  728. })
  729. }
  730. }
  731. pub struct SkLookup {
  732. item: ItemFn,
  733. name: Option<String>,
  734. }
  735. impl SkLookup {
  736. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SkLookup> {
  737. let name = name_arg(&mut args)?;
  738. Ok(SkLookup { item, name })
  739. }
  740. pub fn expand(&self) -> Result<TokenStream> {
  741. let section_name: std::borrow::Cow<'_, _> = if let Some(name) = &self.name {
  742. format!("sk_lookup/{name}").into()
  743. } else {
  744. "sk_lookup".into()
  745. };
  746. let fn_vis = &self.item.vis;
  747. let fn_name = &self.item.sig.ident;
  748. let item = &self.item;
  749. Ok(quote! {
  750. #[no_mangle]
  751. #[link_section = #section_name]
  752. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sk_lookup) -> u32 {
  753. return #fn_name(::aya_bpf::programs::SkLookupContext::new(ctx));
  754. #item
  755. }
  756. })
  757. }
  758. }
  759. pub struct CgroupDevice {
  760. item: ItemFn,
  761. name: Option<String>,
  762. }
  763. impl CgroupDevice {
  764. pub fn from_syn(mut args: Args, item: ItemFn) -> Result<Self> {
  765. let name = name_arg(&mut args)?;
  766. Ok(CgroupDevice { item, name })
  767. }
  768. pub fn expand(&self) -> Result<TokenStream> {
  769. let section_name: std::borrow::Cow<'_, _> = if let Some(name) = &self.name {
  770. format!("cgroup/dev/{name}").into()
  771. } else {
  772. "cgroup/dev".into()
  773. };
  774. let fn_vis = &self.item.vis;
  775. let fn_name = &self.item.sig.ident;
  776. let item = &self.item;
  777. Ok(quote! {
  778. #[no_mangle]
  779. #[link_section = #section_name]
  780. #fn_vis fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_cgroup_dev_ctx) -> i32 {
  781. return #fn_name(::aya_bpf::programs::DeviceContext::new(ctx));
  782. #item
  783. }
  784. })
  785. }
  786. }
  787. #[cfg(test)]
  788. mod tests {
  789. use syn::parse_quote;
  790. use super::*;
  791. #[test]
  792. fn cgroup_skb_with_attach_and_name() {
  793. let prog = CgroupSkb::from_syn(
  794. parse_quote!(name = "foo", attach = "ingress"),
  795. parse_quote!(
  796. fn foo(ctx: SkBuffContext) -> i32 {
  797. 0
  798. }
  799. ),
  800. )
  801. .unwrap();
  802. let stream = prog.expand().unwrap();
  803. assert!(stream
  804. .to_string()
  805. .contains("[link_section = \"cgroup_skb/ingress/foo\"]"));
  806. }
  807. #[test]
  808. fn cgroup_skb_with_name() {
  809. let prog = CgroupSkb::from_syn(
  810. parse_quote!(name = "foo"),
  811. parse_quote!(
  812. fn foo(ctx: SkBuffContext) -> i32 {
  813. 0
  814. }
  815. ),
  816. )
  817. .unwrap();
  818. let stream = prog.expand().unwrap();
  819. assert!(stream
  820. .to_string()
  821. .contains("[link_section = \"cgroup/skb/foo\"]"));
  822. }
  823. #[test]
  824. fn cgroup_skb_no_name() {
  825. let prog = CgroupSkb::from_syn(
  826. parse_quote!(),
  827. parse_quote!(
  828. fn foo(ctx: SkBuffContext) -> i32 {
  829. 0
  830. }
  831. ),
  832. )
  833. .unwrap();
  834. let stream = prog.expand().unwrap();
  835. assert!(stream
  836. .to_string()
  837. .contains("[link_section = \"cgroup/skb\"]"));
  838. }
  839. #[test]
  840. fn cgroup_skb_with_attach_no_name() {
  841. let prog = CgroupSkb::from_syn(
  842. parse_quote!(attach = "egress"),
  843. parse_quote!(
  844. fn foo(ctx: SkBuffContext) -> i32 {
  845. 0
  846. }
  847. ),
  848. )
  849. .unwrap();
  850. let stream = prog.expand().unwrap();
  851. assert!(stream
  852. .to_string()
  853. .contains("[link_section = \"cgroup_skb/egress\"]"));
  854. }
  855. #[test]
  856. fn cgroup_device_no_name() {
  857. let prog = CgroupDevice::from_syn(
  858. parse_quote!(),
  859. parse_quote!(
  860. fn foo(ctx: DeviceContext) -> i32 {
  861. 0
  862. }
  863. ),
  864. )
  865. .unwrap();
  866. let stream = prog.expand().unwrap();
  867. assert!(stream
  868. .to_string()
  869. .contains("[link_section = \"cgroup/dev\"]"));
  870. }
  871. #[test]
  872. fn priv_function() {
  873. let prog = CgroupSkb::from_syn(
  874. parse_quote!(attach = "egress"),
  875. parse_quote!(
  876. fn foo(ctx: SkBuffContext) -> i32 {
  877. 0
  878. }
  879. ),
  880. )
  881. .unwrap();
  882. let stream = prog.expand().unwrap();
  883. assert!(stream.to_string().contains("] fn foo ("));
  884. }
  885. #[test]
  886. fn pub_function() {
  887. let prog = CgroupSkb::from_syn(
  888. parse_quote!(attach = "egress"),
  889. parse_quote!(
  890. pub fn foo(ctx: SkBuffContext) -> i32 {
  891. 0
  892. }
  893. ),
  894. )
  895. .unwrap();
  896. let stream = prog.expand().unwrap();
  897. assert!(stream.to_string().contains("] pub fn foo ("));
  898. }
  899. #[test]
  900. fn pub_crate_function() {
  901. let prog = CgroupSkb::from_syn(
  902. parse_quote!(attach = "egress"),
  903. parse_quote!(
  904. pub(crate) fn foo(ctx: SkBuffContext) -> i32 {
  905. 0
  906. }
  907. ),
  908. )
  909. .unwrap();
  910. let stream = prog.expand().unwrap();
  911. assert!(stream.to_string().contains("] pub (crate) fn foo ("));
  912. }
  913. }