aya_ebpf_macros/lib.rs
1#![cfg_attr(test, expect(unused_crate_dependencies, reason = "used in doctests"))]
2
3pub(crate) mod args;
4mod btf_map;
5mod btf_tracepoint;
6mod cgroup_device;
7mod cgroup_skb;
8mod cgroup_sock;
9mod cgroup_sock_addr;
10mod cgroup_sockopt;
11mod cgroup_sysctl;
12mod fentry;
13mod fexit;
14mod flow_dissector;
15mod kprobe;
16mod lsm;
17mod lsm_cgroup;
18mod map;
19mod perf_event;
20mod raw_tracepoint;
21mod sk_lookup;
22mod sk_msg;
23mod sk_skb;
24mod sock_ops;
25mod socket_filter;
26mod tc;
27mod tracepoint;
28mod uprobe;
29mod xdp;
30
31use btf_map::BtfMap;
32use btf_tracepoint::BtfTracePoint;
33use cgroup_device::CgroupDevice;
34use cgroup_skb::CgroupSkb;
35use cgroup_sock::CgroupSock;
36use cgroup_sock_addr::CgroupSockAddr;
37use cgroup_sockopt::CgroupSockopt;
38use cgroup_sysctl::CgroupSysctl;
39use fentry::FEntry;
40use fexit::FExit;
41use flow_dissector::FlowDissector;
42use kprobe::{KProbe, KProbeKind};
43use lsm::Lsm;
44use lsm_cgroup::LsmCgroup;
45use map::Map;
46use perf_event::PerfEvent;
47use proc_macro::TokenStream;
48use raw_tracepoint::RawTracePoint;
49use sk_lookup::SkLookup;
50use sk_msg::SkMsg;
51use sk_skb::{SkSkb, SkSkbKind};
52use sock_ops::SockOps;
53use socket_filter::SocketFilter;
54use tc::SchedClassifier;
55use tracepoint::TracePoint;
56use uprobe::{UProbe, UProbeKind};
57use xdp::Xdp;
58
59#[proc_macro_attribute]
60pub fn btf_map(attrs: TokenStream, item: TokenStream) -> TokenStream {
61 match BtfMap::parse(attrs.into(), item.into()) {
62 Ok(prog) => prog.expand(),
63 Err(err) => err.into_compile_error(),
64 }
65 .into()
66}
67
68#[proc_macro_attribute]
69pub fn map(attrs: TokenStream, item: TokenStream) -> TokenStream {
70 match Map::parse(attrs.into(), item.into()) {
71 Ok(prog) => prog.expand(),
72 Err(err) => err.into_compile_error(),
73 }
74 .into()
75}
76#[proc_macro_attribute]
77pub fn kprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
78 match KProbe::parse(KProbeKind::KProbe, attrs.into(), item.into()) {
79 Ok(prog) => prog.expand(),
80 Err(err) => err.emit_as_expr_tokens(),
81 }
82 .into()
83}
84#[proc_macro_attribute]
85pub fn kretprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
86 match KProbe::parse(KProbeKind::KRetProbe, attrs.into(), item.into()) {
87 Ok(prog) => prog.expand(),
88 Err(err) => err.emit_as_expr_tokens(),
89 }
90 .into()
91}
92#[proc_macro_attribute]
93pub fn uprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
94 match UProbe::parse(UProbeKind::UProbe, attrs.into(), item.into()) {
95 Ok(prog) => match prog.expand() {
96 Ok(tokens) => tokens,
97 Err(err) => err.emit_as_expr_tokens(),
98 },
99 Err(err) => err.emit_as_expr_tokens(),
100 }
101 .into()
102}
103#[proc_macro_attribute]
104pub fn uretprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
105 match UProbe::parse(UProbeKind::URetProbe, attrs.into(), item.into()) {
106 Ok(prog) => match prog.expand() {
107 Ok(tokens) => tokens,
108 Err(err) => err.emit_as_expr_tokens(),
109 },
110 Err(err) => err.emit_as_expr_tokens(),
111 }
112 .into()
113}
114#[proc_macro_attribute]
115pub fn sock_ops(attrs: TokenStream, item: TokenStream) -> TokenStream {
116 match SockOps::parse(attrs.into(), item.into()) {
117 Ok(prog) => prog.expand(),
118 Err(err) => err.emit_as_expr_tokens(),
119 }
120 .into()
121}
122
123#[proc_macro_attribute]
124pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream {
125 match SkMsg::parse(attrs.into(), item.into()) {
126 Ok(prog) => prog.expand(),
127 Err(err) => err.emit_as_expr_tokens(),
128 }
129 .into()
130}
131
132/// Marks a function as an eBPF XDP program that can be attached to a network interface.
133///
134/// On some NIC drivers, XDP probes are compatible with jumbo frames through the use of
135/// multi-buffer packets. Programs can opt-in this support by passing the `frags` argument.
136///
137/// XDP programs can also be chained through the use of CPU maps and dev maps, but must opt-in
138/// with the `map = "cpumap"` or `map = "devmap"` arguments.
139///
140/// # Minimum kernel version
141///
142/// The minimum kernel version required to use this feature is 4.8.
143///
144/// # Examples
145///
146/// ```no_run
147/// use aya_ebpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext};
148///
149/// #[xdp(frags)]
150/// pub fn xdp(ctx: XdpContext) -> u32 {
151/// XDP_PASS
152/// }
153/// ```
154#[proc_macro_attribute]
155pub fn xdp(attrs: TokenStream, item: TokenStream) -> TokenStream {
156 match Xdp::parse(attrs.into(), item.into()) {
157 Ok(prog) => prog.expand(),
158 Err(err) => err.emit_as_expr_tokens(),
159 }
160 .into()
161}
162#[proc_macro_attribute]
163pub fn classifier(attrs: TokenStream, item: TokenStream) -> TokenStream {
164 match SchedClassifier::parse(attrs.into(), item.into()) {
165 Ok(prog) => prog.expand(),
166 Err(err) => err.emit_as_expr_tokens(),
167 }
168 .into()
169}
170
171#[proc_macro_attribute]
172pub fn cgroup_sysctl(attrs: TokenStream, item: TokenStream) -> TokenStream {
173 match CgroupSysctl::parse(attrs.into(), item.into()) {
174 Ok(prog) => prog.expand(),
175 Err(err) => err.emit_as_expr_tokens(),
176 }
177 .into()
178}
179#[proc_macro_attribute]
180pub fn cgroup_sockopt(attrs: TokenStream, item: TokenStream) -> TokenStream {
181 match CgroupSockopt::parse(attrs.into(), item.into()) {
182 Ok(prog) => prog.expand(),
183 Err(err) => err.emit_as_expr_tokens(),
184 }
185 .into()
186}
187#[proc_macro_attribute]
188pub fn cgroup_skb(attrs: TokenStream, item: TokenStream) -> TokenStream {
189 match CgroupSkb::parse(attrs.into(), item.into()) {
190 Ok(prog) => prog.expand(),
191 Err(err) => err.emit_as_expr_tokens(),
192 }
193 .into()
194}
195
196/// Marks a function as a [`CgroupSockAddr`] eBPF program.
197///
198/// [`CgroupSockAddr`] programs can be used to inspect or modify socket addresses passed to
199/// various syscalls within a [cgroup]. The `attach_type` argument specifies a place to attach
200/// the eBPF program to. See [`CgroupSockAddrAttachType`] for more details.
201///
202/// [cgroup]: https://man7.org/linux/man-pages/man7/cgroups.7.html
203/// [`CgroupSockAddrAttachType`]: ../aya/programs/cgroup_sock_addr/enum.CgroupSockAddrAttachType.html
204/// [`CgroupSockAddr`]: ../aya/programs/cgroup_sock_addr/struct.CgroupSockAddr.html
205///
206/// # Minimum kernel version
207///
208/// The minimum kernel version required to use this feature is 4.17.
209///
210/// # Examples
211///
212/// ```no_run
213/// use aya_ebpf::{macros::cgroup_sock_addr, programs::SockAddrContext};
214///
215/// #[cgroup_sock_addr(connect4)]
216/// pub fn connect4(ctx: SockAddrContext) -> i32 {
217/// match try_connect4(ctx) {
218/// Ok(ret) => ret,
219/// Err(ret) => ret,
220/// }
221/// }
222///
223/// fn try_connect4(ctx: SockAddrContext) -> Result<i32, i32> {
224/// Ok(0)
225/// }
226/// ```
227#[proc_macro_attribute]
228pub fn cgroup_sock_addr(attrs: TokenStream, item: TokenStream) -> TokenStream {
229 match CgroupSockAddr::parse(attrs.into(), item.into()) {
230 Ok(prog) => prog.expand(),
231 Err(err) => err.emit_as_expr_tokens(),
232 }
233 .into()
234}
235#[proc_macro_attribute]
236pub fn cgroup_sock(attrs: TokenStream, item: TokenStream) -> TokenStream {
237 match CgroupSock::parse(attrs.into(), item.into()) {
238 Ok(prog) => prog.expand(),
239 Err(err) => err.emit_as_expr_tokens(),
240 }
241 .into()
242}
243
244#[proc_macro_attribute]
245pub fn tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
246 match TracePoint::parse(attrs.into(), item.into()) {
247 Ok(prog) => prog.expand(),
248 Err(err) => err.emit_as_expr_tokens(),
249 }
250 .into()
251}
252
253#[proc_macro_attribute]
254pub fn perf_event(attrs: TokenStream, item: TokenStream) -> TokenStream {
255 match PerfEvent::parse(attrs.into(), item.into()) {
256 Ok(prog) => prog.expand(),
257 Err(err) => err.emit_as_expr_tokens(),
258 }
259 .into()
260}
261
262/// Marks a function as a raw tracepoint eBPF program that can be attached at a
263/// pre-defined kernel trace point.
264///
265/// The kernel provides a set of pre-defined trace points that eBPF programs can
266/// be attached to. See `/sys/kernel/debug/tracing/events` for a list of which
267/// events can be traced.
268///
269/// # Minimum kernel version
270///
271/// The minimum kernel version required to use this feature is 4.7.
272///
273/// # Examples
274///
275/// ```no_run
276/// use aya_ebpf::{macros::raw_tracepoint, programs::RawTracePointContext};
277///
278/// #[raw_tracepoint(tracepoint = "sys_enter")]
279/// pub fn sys_enter(ctx: RawTracePointContext) -> i32 {
280/// match unsafe { try_sys_enter(ctx) } {
281/// Ok(ret) => ret,
282/// Err(ret) => ret,
283/// }
284/// }
285///
286/// unsafe fn try_sys_enter(_ctx: RawTracePointContext) -> Result<i32, i32> {
287/// Ok(0)
288/// }
289/// ```
290#[proc_macro_attribute]
291pub fn raw_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
292 match RawTracePoint::parse(attrs.into(), item.into()) {
293 Ok(prog) => prog.expand(),
294 Err(err) => err.into_compile_error(),
295 }
296 .into()
297}
298
299/// Marks a function as an LSM program that can be attached to Linux LSM hooks.
300/// Used to implement security policy and audit logging.
301///
302/// The hook name is the first argument to the macro.
303/// You may also provide `sleepable` to mark the program as sleepable.
304/// Arguments should be comma separated.
305///
306/// LSM probes can be attached to the kernel's security hooks to implement mandatory
307/// access control policy and security auditing.
308///
309/// LSM probes require a kernel compiled with `CONFIG_BPF_LSM=y` and `CONFIG_DEBUG_INFO_BTF=y`.
310/// In order for the probes to fire, you also need the BPF LSM to be enabled through your
311/// kernel's boot parameters (like `lsm=lockdown,yama,bpf`).
312///
313/// # Minimum kernel version
314///
315/// The minimum kernel version required to use this feature is 5.7.
316///
317/// # Examples
318///
319/// ```no_run
320/// use aya_ebpf::{macros::lsm, programs::LsmContext};
321///
322/// #[lsm(hook = "file_open")]
323/// pub fn file_open(ctx: LsmContext) -> i32 {
324/// match unsafe { try_file_open(ctx) } {
325/// Ok(ret) => ret,
326/// Err(ret) => ret,
327/// }
328/// }
329///
330/// unsafe fn try_file_open(_ctx: LsmContext) -> Result<i32, i32> {
331/// Ok(0)
332/// }
333/// ```
334#[proc_macro_attribute]
335pub fn lsm(attrs: TokenStream, item: TokenStream) -> TokenStream {
336 match Lsm::parse(attrs.into(), item.into()) {
337 Ok(prog) => prog.expand(),
338 Err(err) => err.into_compile_error(),
339 }
340 .into()
341}
342
343/// Marks a function as an LSM program that can be attached to cgroups.
344/// This program will only trigger for workloads in the attached cgroups.
345/// Used to implement security policy and audit logging.
346///
347/// The hook name is the first and only argument to the macro.
348///
349/// LSM probes can be attached to the kernel's security hooks to implement mandatory
350/// access control policy and security auditing.
351///
352/// LSM probes require a kernel compiled with `CONFIG_BPF_LSM=y` and `CONFIG_DEBUG_INFO_BTF=y`.
353/// In order for the probes to fire, you also need the BPF LSM to be enabled through your
354/// kernel's boot parameters (like `lsm=lockdown,yama,bpf`).
355///
356/// # Minimum kernel version
357///
358/// The minimum kernel version required to use this feature is 6.0.
359///
360/// # Examples
361///
362/// ```no_run
363/// use aya_ebpf::{macros::lsm_cgroup, programs::LsmContext};
364///
365/// #[lsm_cgroup(hook = "file_open")]
366/// pub fn file_open(ctx: LsmContext) -> i32 {
367/// match unsafe { try_file_open(ctx) } {
368/// Ok(ret) => ret,
369/// Err(ret) => ret,
370/// }
371/// }
372///
373/// unsafe fn try_file_open(_ctx: LsmContext) -> Result<i32, i32> {
374/// Err(0)
375/// }
376/// ```
377#[proc_macro_attribute]
378pub fn lsm_cgroup(attrs: TokenStream, item: TokenStream) -> TokenStream {
379 match LsmCgroup::parse(attrs.into(), item.into()) {
380 Ok(prog) => prog.expand(),
381 Err(err) => err.into_compile_error(),
382 }
383 .into()
384}
385
386/// Marks a function as a [BTF-enabled raw tracepoint][1] eBPF program that can be attached at
387/// a pre-defined kernel trace point.
388///
389/// The kernel provides a set of pre-defined trace points that eBPF programs can
390/// be attached to. See `/sys/kernel/debug/tracing/events` for a list of which
391/// events can be traced.
392///
393/// # Minimum kernel version
394///
395/// The minimum kernel version required to use this feature is 5.5.
396///
397/// # Examples
398///
399/// ```no_run
400/// use aya_ebpf::{macros::btf_tracepoint, programs::BtfTracePointContext};
401///
402/// #[btf_tracepoint(function = "sched_process_fork")]
403/// pub fn sched_process_fork(ctx: BtfTracePointContext) -> u32 {
404/// match unsafe { try_sched_process_fork(ctx) } {
405/// Ok(ret) => ret,
406/// Err(ret) => ret,
407/// }
408/// }
409///
410/// unsafe fn try_sched_process_fork(_ctx: BtfTracePointContext) -> Result<u32, u32> {
411/// Ok(0)
412/// }
413/// ```
414///
415/// [1]: https://github.com/torvalds/linux/commit/9e15db66136a14cde3f35691f1d839d950118826
416#[proc_macro_attribute]
417pub fn btf_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
418 match BtfTracePoint::parse(attrs.into(), item.into()) {
419 Ok(prog) => prog.expand(),
420 Err(err) => err.into_compile_error(),
421 }
422 .into()
423}
424
425/// Marks a function as a SK_SKB Stream Parser eBPF program that can be attached
426/// to a SockMap
427///
428/// # Minimum kernel version
429///
430/// The minimum kernel version required to use this feature is 4.14
431///
432/// # Examples
433///
434/// ```no_run
435/// use aya_ebpf::{macros::stream_parser, programs::SkBuffContext};
436///
437///
438///#[stream_parser]
439///fn stream_parser(ctx: SkBuffContext) -> u32 {
440/// match try_stream_parser(ctx) {
441/// Ok(ret) => ret,
442/// Err(ret) => ret,
443/// }
444///}
445///
446///fn try_stream_parser(ctx: SkBuffContext) -> Result<u32, u32> {
447/// Ok(ctx.len())
448///}
449/// ```
450#[proc_macro_attribute]
451pub fn stream_parser(attrs: TokenStream, item: TokenStream) -> TokenStream {
452 sk_skb(SkSkbKind::StreamParser, attrs, item)
453}
454
455/// Marks a function as a SK_SKB Stream Verdict eBPF program that can be attached
456/// to a SockMap
457///
458/// # Minimum kernel version
459///
460/// The minimum kernel version required to use this feature is 4.14
461///
462/// # Examples
463///
464/// ```no_run
465/// use aya_ebpf::{macros::stream_verdict, programs::SkBuffContext, bindings::sk_action};
466///
467///
468///#[stream_verdict]
469///fn stream_verdict(ctx: SkBuffContext) -> u32 {
470/// match try_stream_verdict(ctx) {
471/// Ok(ret) => ret,
472/// Err(ret) => ret,
473/// }
474///}
475///
476///fn try_stream_verdict(_ctx: SkBuffContext) -> Result<u32, u32> {
477/// Ok(sk_action::SK_PASS)
478///}
479/// ```
480#[proc_macro_attribute]
481pub fn stream_verdict(attrs: TokenStream, item: TokenStream) -> TokenStream {
482 sk_skb(SkSkbKind::StreamVerdict, attrs, item)
483}
484
485fn sk_skb(kind: SkSkbKind, attrs: TokenStream, item: TokenStream) -> TokenStream {
486 match SkSkb::parse(kind, attrs.into(), item.into()) {
487 Ok(prog) => prog.expand(),
488 Err(err) => err.emit_as_expr_tokens(),
489 }
490 .into()
491}
492
493/// Marks a function as a eBPF Socket Filter program that can be attached to
494/// a socket.
495///
496/// # Minimum kernel version
497///
498/// The minimum kernel version required to use this feature is 3.19
499///
500/// # Examples
501///
502/// ```no_run
503/// use aya_ebpf::{macros::socket_filter, programs::SkBuffContext};
504///
505/// #[socket_filter]
506/// pub fn accept_all(_ctx: SkBuffContext) -> i64 {
507/// 0
508/// }
509/// ```
510#[proc_macro_attribute]
511pub fn socket_filter(attrs: TokenStream, item: TokenStream) -> TokenStream {
512 match SocketFilter::parse(attrs.into(), item.into()) {
513 Ok(prog) => prog.expand(),
514 Err(err) => err.emit_as_expr_tokens(),
515 }
516 .into()
517}
518
519/// Marks a function as a fentry eBPF program that can be attached to almost
520/// any function inside the kernel. The difference between fentry and kprobe
521/// is that fexit has practically zero overhead to call before kernel function.
522/// fentry programs can be also attached to other eBPF programs.
523///
524/// # Minimumm kernel version
525///
526/// The minimum kernel version required to use this feature is 5.5.
527///
528/// # Examples
529///
530/// ```no_run
531/// use aya_ebpf::{macros::fentry, programs::FEntryContext};
532/// # #[expect(non_camel_case_types)]
533/// # type filename = u32;
534/// # #[expect(non_camel_case_types)]
535/// # type path = u32;
536///
537/// #[fentry(function = "filename_lookup")]
538/// fn filename_lookup(ctx: FEntryContext) -> i32 {
539/// match unsafe { try_filename_lookup(ctx) } {
540/// Ok(ret) => ret,
541/// Err(ret) => ret,
542/// }
543/// }
544///
545/// unsafe fn try_filename_lookup(ctx: FEntryContext) -> Result<i32, i32> {
546/// let _f: *const filename = ctx.arg(1);
547/// let _p: *const path = ctx.arg(3);
548///
549/// Ok(0)
550/// }
551/// ```
552#[proc_macro_attribute]
553pub fn fentry(attrs: TokenStream, item: TokenStream) -> TokenStream {
554 match FEntry::parse(attrs.into(), item.into()) {
555 Ok(prog) => prog.expand(),
556 Err(err) => err.into_compile_error(),
557 }
558 .into()
559}
560
561/// Marks a function as a fexit eBPF program that can be attached to almost
562/// any function inside the kernel. The difference between fexit and kretprobe
563/// is that fexit has practically zero overhead to call after kernel function
564/// and it focuses on access to arguments rather than the return value. fexit
565/// programs can be also attached to other eBPF programs
566///
567/// # Minimumm kernel version
568///
569/// The minimum kernel version required to use this feature is 5.5.
570///
571/// # Examples
572///
573/// ```no_run
574/// use aya_ebpf::{macros::fexit, programs::FExitContext};
575/// # #[expect(non_camel_case_types)]
576/// # type filename = u32;
577/// # #[expect(non_camel_case_types)]
578/// # type path = u32;
579///
580/// #[fexit(function = "filename_lookup")]
581/// fn filename_lookup(ctx: FExitContext) -> i32 {
582/// match unsafe { try_filename_lookup(ctx) } {
583/// Ok(ret) => ret,
584/// Err(ret) => ret,
585/// }
586/// }
587///
588/// unsafe fn try_filename_lookup(ctx: FExitContext) -> Result<i32, i32> {
589/// let _f: *const filename = ctx.arg(1);
590/// let _p: *const path = ctx.arg(3);
591///
592/// Ok(0)
593/// }
594/// ```
595#[proc_macro_attribute]
596pub fn fexit(attrs: TokenStream, item: TokenStream) -> TokenStream {
597 match FExit::parse(attrs.into(), item.into()) {
598 Ok(prog) => prog.expand(),
599 Err(err) => err.into_compile_error(),
600 }
601 .into()
602}
603
604/// Marks a function as an eBPF Flow Dissector program.
605///
606/// Flow dissector is a program type that parses metadata out of the packets.
607///
608/// BPF flow dissectors can be attached per network namespace. These programs
609/// are given a packet and expected to populate the fields of
610/// `FlowDissectorContext::flow_keys`. The return code of the BPF program is
611/// either [`BPF_OK`] to indicate successful dissection, [`BPF_DROP`] to
612/// indicate parsing error, or [`BPF_FLOW_DISSECTOR_CONTINUE`] to indicate that
613/// no custom dissection was performed, and fallback to standard dissector is
614/// requested.
615///
616/// # Minimum kernel version
617///
618/// The minimum kernel version required to use this feature is 4.20.
619///
620/// # Examples
621///
622/// ```no_run
623/// use aya_ebpf::{bindings::bpf_ret_code, macros::flow_dissector, programs::FlowDissectorContext};
624///
625/// #[flow_dissector]
626/// pub fn dissect(_ctx: FlowDissectorContext) -> u32 {
627/// // TODO: do something useful here.
628/// bpf_ret_code::BPF_FLOW_DISSECTOR_CONTINUE
629/// }
630/// ```
631///
632/// [`FlowDissectorContext::flow_keys`]: ../aya_ebpf/programs/flow_dissector/struct.FlowDissectorContext.html#method.flow_keys
633/// [`BPF_OK`]: ../aya_ebpf/bindings/bpf_ret_code/constant.bpf_ok
634/// [`BPF_DROP`]: ../aya_ebpf/bindings/bpf_ret_code/constant.bpf_drop
635/// [`BPF_FLOW_DISSECTOR_CONTINUE`]: ../aya_ebpf/bindings/bpf_ret_code/constant.bpf_flow_dissector_continue
636#[proc_macro_attribute]
637pub fn flow_dissector(attrs: TokenStream, item: TokenStream) -> TokenStream {
638 match FlowDissector::parse(attrs.into(), item.into()) {
639 Ok(prog) => prog.expand(),
640 Err(err) => err.emit_as_expr_tokens(),
641 }
642 .into()
643}
644
645/// Marks a function as an eBPF Socket Lookup program that can be attached to
646/// a network namespace.
647///
648/// # Minimum kernel version
649///
650/// The minimum kernel version required to use this feature is 5.9
651///
652/// # Examples
653///
654/// ```no_run
655/// use aya_ebpf::{macros::sk_lookup, programs::SkLookupContext};
656///
657/// #[sk_lookup]
658/// pub fn accept_all(_ctx: SkLookupContext) -> u32 {
659/// // use sk_assign to redirect
660/// 0
661/// }
662/// ```
663#[proc_macro_attribute]
664pub fn sk_lookup(attrs: TokenStream, item: TokenStream) -> TokenStream {
665 match SkLookup::parse(attrs.into(), item.into()) {
666 Ok(prog) => prog.expand(),
667 Err(err) => err.emit_as_expr_tokens(),
668 }
669 .into()
670}
671
672/// Marks a function as a cgroup device eBPF program that can be attached to a
673/// cgroup.
674///
675/// # Minimum kernel version
676///
677/// The minimum kernel version required to use this feature is 4.15.
678///
679/// # Examples
680///
681/// ```no_run
682/// use aya_ebpf::{
683/// macros::cgroup_device,
684/// programs::DeviceContext,
685/// };
686///
687/// #[cgroup_device]
688/// pub fn cgroup_dev(ctx: DeviceContext) -> i32 {
689/// // Reject all device access
690/// 0
691/// }
692/// ```
693#[proc_macro_attribute]
694pub fn cgroup_device(attrs: TokenStream, item: TokenStream) -> TokenStream {
695 match CgroupDevice::parse(attrs.into(), item.into()) {
696 Ok(prog) => prog.expand(),
697 Err(err) => err.emit_as_expr_tokens(),
698 }
699 .into()
700}