xdp.rs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. use proc_macro2::TokenStream;
  2. use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
  3. use quote::quote;
  4. use syn::{ItemFn, spanned::Spanned as _};
  5. use crate::args::{Args, err_on_unknown_args, pop_bool_arg, pop_string_arg};
  6. pub(crate) struct Xdp {
  7. item: ItemFn,
  8. frags: bool,
  9. map: Option<XdpMap>,
  10. }
  11. #[derive(Clone, Copy)]
  12. pub(crate) enum XdpMap {
  13. CpuMap,
  14. DevMap,
  15. }
  16. impl Xdp {
  17. pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
  18. let item = syn::parse2(item)?;
  19. let span = attrs.span();
  20. let mut args: Args = syn::parse2(attrs)?;
  21. let frags = pop_bool_arg(&mut args, "frags");
  22. let map = match pop_string_arg(&mut args, "map").as_deref() {
  23. Some("cpumap") => Some(XdpMap::CpuMap),
  24. Some("devmap") => Some(XdpMap::DevMap),
  25. Some(name) => {
  26. return Err(span.error(format!(
  27. "Invalid value. Expected 'cpumap' or 'devmap', found '{name}'"
  28. )));
  29. }
  30. None => None,
  31. };
  32. err_on_unknown_args(&args)?;
  33. Ok(Self { item, frags, map })
  34. }
  35. pub(crate) fn expand(&self) -> TokenStream {
  36. let Self { item, frags, map } = self;
  37. let ItemFn {
  38. attrs: _,
  39. vis,
  40. sig,
  41. block: _,
  42. } = item;
  43. let mut section_name = vec![if *frags { "xdp.frags" } else { "xdp" }];
  44. match map {
  45. Some(XdpMap::CpuMap) => section_name.push("cpumap"),
  46. Some(XdpMap::DevMap) => section_name.push("devmap"),
  47. None => (),
  48. };
  49. let section_name = section_name.join("/");
  50. let fn_name = &sig.ident;
  51. quote! {
  52. #[unsafe(no_mangle)]
  53. #[unsafe(link_section = #section_name)]
  54. #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  55. return #fn_name(::aya_ebpf::programs::XdpContext::new(ctx));
  56. #item
  57. }
  58. }
  59. }
  60. }
  61. #[cfg(test)]
  62. mod tests {
  63. use syn::parse_quote;
  64. use super::*;
  65. #[test]
  66. fn test_xdp() {
  67. let prog = Xdp::parse(
  68. parse_quote! {},
  69. parse_quote! {
  70. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  71. 0
  72. }
  73. },
  74. )
  75. .unwrap();
  76. let expanded = prog.expand();
  77. let expected = quote! {
  78. #[unsafe(no_mangle)]
  79. #[unsafe(link_section = "xdp")]
  80. fn prog(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  81. return prog(::aya_ebpf::programs::XdpContext::new(ctx));
  82. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  83. 0
  84. }
  85. }
  86. };
  87. assert_eq!(expected.to_string(), expanded.to_string());
  88. }
  89. #[test]
  90. fn test_xdp_frags() {
  91. let prog = Xdp::parse(
  92. parse_quote! { frags },
  93. parse_quote! {
  94. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  95. 0
  96. }
  97. },
  98. )
  99. .unwrap();
  100. let expanded = prog.expand();
  101. let expected = quote! {
  102. #[unsafe(no_mangle)]
  103. #[unsafe(link_section = "xdp.frags")]
  104. fn prog(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  105. return prog(::aya_ebpf::programs::XdpContext::new(ctx));
  106. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  107. 0
  108. }
  109. }
  110. };
  111. assert_eq!(expected.to_string(), expanded.to_string());
  112. }
  113. #[test]
  114. fn test_xdp_cpumap() {
  115. let prog = Xdp::parse(
  116. parse_quote! { map = "cpumap" },
  117. parse_quote! {
  118. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  119. 0
  120. }
  121. },
  122. )
  123. .unwrap();
  124. let expanded = prog.expand();
  125. let expected = quote! {
  126. #[unsafe(no_mangle)]
  127. #[unsafe(link_section = "xdp/cpumap")]
  128. fn prog(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  129. return prog(::aya_ebpf::programs::XdpContext::new(ctx));
  130. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  131. 0
  132. }
  133. }
  134. };
  135. assert_eq!(expected.to_string(), expanded.to_string());
  136. }
  137. #[test]
  138. fn test_xdp_devmap() {
  139. let prog = Xdp::parse(
  140. parse_quote! { map = "devmap" },
  141. parse_quote! {
  142. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  143. 0
  144. }
  145. },
  146. )
  147. .unwrap();
  148. let expanded = prog.expand();
  149. let expected = quote! {
  150. #[unsafe(no_mangle)]
  151. #[unsafe(link_section = "xdp/devmap")]
  152. fn prog(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  153. return prog(::aya_ebpf::programs::XdpContext::new(ctx));
  154. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  155. 0
  156. }
  157. }
  158. };
  159. assert_eq!(expected.to_string(), expanded.to_string());
  160. }
  161. #[test]
  162. #[should_panic(expected = "Invalid value. Expected 'cpumap' or 'devmap', found 'badmap'")]
  163. fn test_xdp_bad_map() {
  164. Xdp::parse(
  165. parse_quote! { map = "badmap" },
  166. parse_quote! {
  167. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  168. 0
  169. }
  170. },
  171. )
  172. .unwrap();
  173. }
  174. #[test]
  175. fn test_xdp_frags_cpumap() {
  176. let prog = Xdp::parse(
  177. parse_quote! { frags, map = "cpumap" },
  178. parse_quote! {
  179. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  180. 0
  181. }
  182. },
  183. )
  184. .unwrap();
  185. let expanded = prog.expand();
  186. let expected = quote! {
  187. #[unsafe(no_mangle)]
  188. #[unsafe(link_section = "xdp.frags/cpumap")]
  189. fn prog(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  190. return prog(::aya_ebpf::programs::XdpContext::new(ctx));
  191. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  192. 0
  193. }
  194. }
  195. };
  196. assert_eq!(expected.to_string(), expanded.to_string());
  197. }
  198. #[test]
  199. fn test_xdp_frags_devmap() {
  200. let prog = Xdp::parse(
  201. parse_quote! { frags, map = "devmap" },
  202. parse_quote! {
  203. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  204. 0
  205. }
  206. },
  207. )
  208. .unwrap();
  209. let expanded = prog.expand();
  210. let expected = quote! {
  211. #[unsafe(no_mangle)]
  212. #[unsafe(link_section = "xdp.frags/devmap")]
  213. fn prog(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
  214. return prog(::aya_ebpf::programs::XdpContext::new(ctx));
  215. fn prog(ctx: &mut ::aya_ebpf::programs::XdpContext) -> i32 {
  216. 0
  217. }
  218. }
  219. };
  220. assert_eq!(expected.to_string(), expanded.to_string());
  221. }
  222. }