Skip to main content

ebpf_api/
program_type.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use ebpf::{
6    CallingContext, CbpfConfig, CbpfLenInstruction, FieldDescriptor, FieldType, FunctionSignature,
7    HelperDefinition, MapSchema, MapTypeFilter, MemoryId, MemoryParameterSize, StructDescriptor,
8    Type,
9};
10use fidl_fuchsia_ebpf as febpf;
11use linux_uapi::{
12    __sk_buff, bpf_attach_type_BPF_CGROUP_DEVICE, bpf_attach_type_BPF_CGROUP_GETSOCKOPT,
13    bpf_attach_type_BPF_CGROUP_INET_EGRESS, bpf_attach_type_BPF_CGROUP_INET_INGRESS,
14    bpf_attach_type_BPF_CGROUP_INET_SOCK_CREATE, bpf_attach_type_BPF_CGROUP_INET_SOCK_RELEASE,
15    bpf_attach_type_BPF_CGROUP_INET4_BIND, bpf_attach_type_BPF_CGROUP_INET4_CONNECT,
16    bpf_attach_type_BPF_CGROUP_INET4_GETPEERNAME, bpf_attach_type_BPF_CGROUP_INET4_GETSOCKNAME,
17    bpf_attach_type_BPF_CGROUP_INET4_POST_BIND, bpf_attach_type_BPF_CGROUP_INET6_BIND,
18    bpf_attach_type_BPF_CGROUP_INET6_CONNECT, bpf_attach_type_BPF_CGROUP_INET6_GETPEERNAME,
19    bpf_attach_type_BPF_CGROUP_INET6_GETSOCKNAME, bpf_attach_type_BPF_CGROUP_INET6_POST_BIND,
20    bpf_attach_type_BPF_CGROUP_SETSOCKOPT, bpf_attach_type_BPF_CGROUP_SOCK_OPS,
21    bpf_attach_type_BPF_CGROUP_SYSCTL, bpf_attach_type_BPF_CGROUP_UDP4_RECVMSG,
22    bpf_attach_type_BPF_CGROUP_UDP4_SENDMSG, bpf_attach_type_BPF_CGROUP_UDP6_RECVMSG,
23    bpf_attach_type_BPF_CGROUP_UDP6_SENDMSG, bpf_attach_type_BPF_CGROUP_UNIX_CONNECT,
24    bpf_attach_type_BPF_CGROUP_UNIX_GETPEERNAME, bpf_attach_type_BPF_CGROUP_UNIX_GETSOCKNAME,
25    bpf_attach_type_BPF_CGROUP_UNIX_RECVMSG, bpf_attach_type_BPF_CGROUP_UNIX_SENDMSG,
26    bpf_attach_type_BPF_FLOW_DISSECTOR, bpf_attach_type_BPF_LIRC_MODE2,
27    bpf_attach_type_BPF_LSM_CGROUP, bpf_attach_type_BPF_LSM_MAC, bpf_attach_type_BPF_MODIFY_RETURN,
28    bpf_attach_type_BPF_NETFILTER, bpf_attach_type_BPF_NETKIT_PEER,
29    bpf_attach_type_BPF_NETKIT_PRIMARY, bpf_attach_type_BPF_PERF_EVENT,
30    bpf_attach_type_BPF_SK_LOOKUP, bpf_attach_type_BPF_SK_MSG_VERDICT,
31    bpf_attach_type_BPF_SK_REUSEPORT_SELECT, bpf_attach_type_BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
32    bpf_attach_type_BPF_SK_SKB_STREAM_PARSER, bpf_attach_type_BPF_SK_SKB_STREAM_VERDICT,
33    bpf_attach_type_BPF_SK_SKB_VERDICT, bpf_attach_type_BPF_STRUCT_OPS,
34    bpf_attach_type_BPF_TCX_EGRESS, bpf_attach_type_BPF_TCX_INGRESS,
35    bpf_attach_type_BPF_TRACE_FENTRY, bpf_attach_type_BPF_TRACE_FEXIT,
36    bpf_attach_type_BPF_TRACE_ITER, bpf_attach_type_BPF_TRACE_KPROBE_MULTI,
37    bpf_attach_type_BPF_TRACE_KPROBE_SESSION, bpf_attach_type_BPF_TRACE_RAW_TP,
38    bpf_attach_type_BPF_TRACE_UPROBE_MULTI, bpf_attach_type_BPF_XDP,
39    bpf_attach_type_BPF_XDP_CPUMAP, bpf_attach_type_BPF_XDP_DEVMAP,
40    bpf_func_id_BPF_FUNC_csum_update, bpf_func_id_BPF_FUNC_get_current_pid_tgid,
41    bpf_func_id_BPF_FUNC_get_current_uid_gid, bpf_func_id_BPF_FUNC_get_netns_cookie,
42    bpf_func_id_BPF_FUNC_get_retval, bpf_func_id_BPF_FUNC_get_smp_processor_id,
43    bpf_func_id_BPF_FUNC_get_socket_cookie, bpf_func_id_BPF_FUNC_get_socket_uid,
44    bpf_func_id_BPF_FUNC_ktime_get_boot_ns, bpf_func_id_BPF_FUNC_ktime_get_coarse_ns,
45    bpf_func_id_BPF_FUNC_ktime_get_ns, bpf_func_id_BPF_FUNC_l3_csum_replace,
46    bpf_func_id_BPF_FUNC_l4_csum_replace, bpf_func_id_BPF_FUNC_map_delete_elem,
47    bpf_func_id_BPF_FUNC_map_lookup_elem, bpf_func_id_BPF_FUNC_map_update_elem,
48    bpf_func_id_BPF_FUNC_probe_read_str, bpf_func_id_BPF_FUNC_probe_read_user,
49    bpf_func_id_BPF_FUNC_probe_read_user_str, bpf_func_id_BPF_FUNC_redirect,
50    bpf_func_id_BPF_FUNC_ringbuf_discard, bpf_func_id_BPF_FUNC_ringbuf_reserve,
51    bpf_func_id_BPF_FUNC_ringbuf_submit, bpf_func_id_BPF_FUNC_set_retval,
52    bpf_func_id_BPF_FUNC_sk_fullsock, bpf_func_id_BPF_FUNC_sk_lookup_tcp,
53    bpf_func_id_BPF_FUNC_sk_lookup_udp, bpf_func_id_BPF_FUNC_sk_release,
54    bpf_func_id_BPF_FUNC_sk_storage_get, bpf_func_id_BPF_FUNC_skb_adjust_room,
55    bpf_func_id_BPF_FUNC_skb_change_head, bpf_func_id_BPF_FUNC_skb_change_proto,
56    bpf_func_id_BPF_FUNC_skb_load_bytes, bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
57    bpf_func_id_BPF_FUNC_skb_pull_data, bpf_func_id_BPF_FUNC_skb_store_bytes,
58    bpf_func_id_BPF_FUNC_trace_printk, bpf_map_type_BPF_MAP_TYPE_RINGBUF,
59    bpf_map_type_BPF_MAP_TYPE_SK_STORAGE, bpf_prog_type_BPF_PROG_TYPE_CGROUP_DEVICE,
60    bpf_prog_type_BPF_PROG_TYPE_CGROUP_SKB, bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK,
61    bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK_ADDR, bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCKOPT,
62    bpf_prog_type_BPF_PROG_TYPE_CGROUP_SYSCTL, bpf_prog_type_BPF_PROG_TYPE_EXT,
63    bpf_prog_type_BPF_PROG_TYPE_FLOW_DISSECTOR, bpf_prog_type_BPF_PROG_TYPE_KPROBE,
64    bpf_prog_type_BPF_PROG_TYPE_LIRC_MODE2, bpf_prog_type_BPF_PROG_TYPE_LSM,
65    bpf_prog_type_BPF_PROG_TYPE_LWT_IN, bpf_prog_type_BPF_PROG_TYPE_LWT_OUT,
66    bpf_prog_type_BPF_PROG_TYPE_LWT_SEG6LOCAL, bpf_prog_type_BPF_PROG_TYPE_LWT_XMIT,
67    bpf_prog_type_BPF_PROG_TYPE_NETFILTER, bpf_prog_type_BPF_PROG_TYPE_PERF_EVENT,
68    bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT,
69    bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, bpf_prog_type_BPF_PROG_TYPE_SCHED_ACT,
70    bpf_prog_type_BPF_PROG_TYPE_SCHED_CLS, bpf_prog_type_BPF_PROG_TYPE_SK_LOOKUP,
71    bpf_prog_type_BPF_PROG_TYPE_SK_MSG, bpf_prog_type_BPF_PROG_TYPE_SK_REUSEPORT,
72    bpf_prog_type_BPF_PROG_TYPE_SK_SKB, bpf_prog_type_BPF_PROG_TYPE_SOCK_OPS,
73    bpf_prog_type_BPF_PROG_TYPE_SOCKET_FILTER, bpf_prog_type_BPF_PROG_TYPE_STRUCT_OPS,
74    bpf_prog_type_BPF_PROG_TYPE_SYSCALL, bpf_prog_type_BPF_PROG_TYPE_TRACEPOINT,
75    bpf_prog_type_BPF_PROG_TYPE_TRACING, bpf_prog_type_BPF_PROG_TYPE_UNSPEC,
76    bpf_prog_type_BPF_PROG_TYPE_XDP, bpf_sock, bpf_sock_addr, bpf_sockopt, bpf_user_pt_regs_t,
77    fuse_bpf_arg, fuse_bpf_args, fuse_entry_bpf_out, fuse_entry_out, seccomp_data, xdp_md,
78};
79use std::collections::HashMap;
80use std::mem::{offset_of, size_of};
81use std::sync::{Arc, LazyLock};
82use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
83
84pub const BPF_PROG_TYPE_FUSE: u32 = 0x77777777;
85
86#[derive(Clone, Default, Debug)]
87pub struct BpfTypeFilter(Vec<ProgramType>);
88
89impl<T: IntoIterator<Item = ProgramType>> From<T> for BpfTypeFilter {
90    fn from(types: T) -> Self {
91        Self(types.into_iter().collect())
92    }
93}
94
95impl BpfTypeFilter {
96    pub fn accept(&self, program_type: ProgramType) -> bool {
97        self.0.is_empty() || self.0.iter().find(|v| **v == program_type).is_some()
98    }
99}
100
101// Map types that should not be allowed in `map_lookup_elem`, `map_update_elem`
102// and `map_delete_elem`.
103static SPECIAL_MAP_TYPES: &[linux_uapi::bpf_map_type] =
104    &[bpf_map_type_BPF_MAP_TYPE_SK_STORAGE, bpf_map_type_BPF_MAP_TYPE_RINGBUF];
105
106static BPF_HELPERS_DEFINITIONS: LazyLock<Vec<(BpfTypeFilter, HelperDefinition)>> =
107    LazyLock::new(|| {
108        vec![
109            (
110                BpfTypeFilter::default(),
111                HelperDefinition {
112                    index: bpf_func_id_BPF_FUNC_map_lookup_elem,
113                    name: "map_lookup_elem",
114                    signature: FunctionSignature {
115                        args: vec![
116                            Type::ConstPtrToMapParameter {
117                                filter: MapTypeFilter::DenyList(SPECIAL_MAP_TYPES),
118                            },
119                            Type::MapKeyParameter { map_ptr_index: 0 },
120                        ],
121                        return_value: Type::NullOrParameter(Box::new(Type::MapValueParameter {
122                            map_ptr_index: 0,
123                        })),
124                        invalidate_array_bounds: false,
125                    },
126                },
127            ),
128            (
129                BpfTypeFilter::default(),
130                HelperDefinition {
131                    index: bpf_func_id_BPF_FUNC_map_update_elem,
132                    name: "map_update_elem",
133                    signature: FunctionSignature {
134                        args: vec![
135                            Type::ConstPtrToMapParameter {
136                                filter: MapTypeFilter::DenyList(SPECIAL_MAP_TYPES),
137                            },
138                            Type::MapKeyParameter { map_ptr_index: 0 },
139                            Type::MapValueParameter { map_ptr_index: 0 },
140                            Type::ScalarValueParameter,
141                        ],
142                        return_value: Type::UNKNOWN_SCALAR,
143                        invalidate_array_bounds: false,
144                    },
145                },
146            ),
147            (
148                BpfTypeFilter::default(),
149                HelperDefinition {
150                    index: bpf_func_id_BPF_FUNC_map_delete_elem,
151                    name: "map_delete_elem",
152                    signature: FunctionSignature {
153                        args: vec![
154                            Type::ConstPtrToMapParameter {
155                                filter: MapTypeFilter::DenyList(SPECIAL_MAP_TYPES),
156                            },
157                            Type::MapKeyParameter { map_ptr_index: 0 },
158                        ],
159                        return_value: Type::UNKNOWN_SCALAR,
160                        invalidate_array_bounds: false,
161                    },
162                },
163            ),
164            (
165                BpfTypeFilter::default(),
166                HelperDefinition {
167                    index: bpf_func_id_BPF_FUNC_trace_printk,
168                    name: "trace_printk",
169                    signature: FunctionSignature {
170                        // TODO("https://fxbug.dev/287120494"): Specify arguments
171                        args: vec![],
172                        return_value: Type::UNKNOWN_SCALAR,
173                        invalidate_array_bounds: false,
174                    },
175                },
176            ),
177            (
178                BpfTypeFilter::default(),
179                HelperDefinition {
180                    index: bpf_func_id_BPF_FUNC_ktime_get_ns,
181                    name: "ktime_get_ns",
182                    signature: FunctionSignature {
183                        args: vec![],
184                        return_value: Type::UNKNOWN_SCALAR,
185                        invalidate_array_bounds: false,
186                    },
187                },
188            ),
189            (
190                BpfTypeFilter::default(),
191                HelperDefinition {
192                    index: bpf_func_id_BPF_FUNC_probe_read_user,
193                    name: "probe_read_user",
194                    signature: FunctionSignature {
195                        args: vec![
196                            Type::MemoryParameter {
197                                size: MemoryParameterSize::Reference { index: 1 },
198                                input: false,
199                                output: true,
200                            },
201                            Type::ScalarValueParameter,
202                            Type::AnyParameter,
203                        ],
204                        return_value: Type::UNKNOWN_SCALAR,
205                        invalidate_array_bounds: false,
206                    },
207                },
208            ),
209            (
210                BpfTypeFilter::default(),
211                HelperDefinition {
212                    index: bpf_func_id_BPF_FUNC_probe_read_user_str,
213                    name: "probe_read_user_str",
214                    signature: FunctionSignature {
215                        args: vec![
216                            Type::MemoryParameter {
217                                size: MemoryParameterSize::Reference { index: 1 },
218                                input: false,
219                                output: true,
220                            },
221                            Type::ScalarValueParameter,
222                            Type::ScalarValueParameter,
223                        ],
224                        return_value: Type::UNKNOWN_SCALAR,
225                        invalidate_array_bounds: false,
226                    },
227                },
228            ),
229            (
230                vec![
231                    ProgramType::CgroupSkb,
232                    ProgramType::SchedAct,
233                    ProgramType::SchedCls,
234                    ProgramType::SocketFilter,
235                ]
236                .into(),
237                HelperDefinition {
238                    index: bpf_func_id_BPF_FUNC_get_socket_uid,
239                    name: "get_socket_uid",
240                    signature: FunctionSignature {
241                        args: vec![Type::StructParameter { id: SK_BUF_ID.clone() }],
242                        return_value: Type::UNKNOWN_SCALAR,
243                        invalidate_array_bounds: false,
244                    },
245                },
246            ),
247            (
248                vec![
249                    ProgramType::CgroupSock,
250                    ProgramType::CgroupSockAddr,
251                    ProgramType::CgroupSockopt,
252                    ProgramType::Fuse,
253                    ProgramType::Kprobe,
254                    ProgramType::Tracepoint,
255                ]
256                .into(),
257                HelperDefinition {
258                    index: bpf_func_id_BPF_FUNC_get_current_uid_gid,
259                    name: "get_current_uid_gid",
260                    signature: FunctionSignature {
261                        args: vec![],
262                        return_value: Type::UNKNOWN_SCALAR,
263                        invalidate_array_bounds: false,
264                    },
265                },
266            ),
267            (
268                vec![
269                    ProgramType::CgroupSock,
270                    ProgramType::CgroupSockAddr,
271                    ProgramType::CgroupSockopt,
272                    ProgramType::Fuse,
273                    ProgramType::Kprobe,
274                    ProgramType::Tracepoint,
275                ]
276                .into(),
277                HelperDefinition {
278                    index: bpf_func_id_BPF_FUNC_get_current_pid_tgid,
279                    name: "get_current_pid_tgid",
280                    signature: FunctionSignature {
281                        args: vec![],
282                        return_value: Type::UNKNOWN_SCALAR,
283                        invalidate_array_bounds: false,
284                    },
285                },
286            ),
287            (
288                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
289                HelperDefinition {
290                    index: bpf_func_id_BPF_FUNC_skb_pull_data,
291                    name: "skb_pull_data",
292                    signature: FunctionSignature {
293                        args: vec![
294                            Type::StructParameter { id: SK_BUF_ID.clone() },
295                            Type::ScalarValueParameter,
296                        ],
297                        return_value: Type::UNKNOWN_SCALAR,
298                        invalidate_array_bounds: true,
299                    },
300                },
301            ),
302            (
303                BpfTypeFilter::default(),
304                HelperDefinition {
305                    index: bpf_func_id_BPF_FUNC_ringbuf_reserve,
306                    name: "ringbuf_reserve",
307                    signature: FunctionSignature {
308                        args: vec![
309                            Type::ConstPtrToMapParameter {
310                                filter: MapTypeFilter::AllowList(&[
311                                    bpf_map_type_BPF_MAP_TYPE_RINGBUF,
312                                ]),
313                            },
314                            Type::ScalarValueParameter,
315                            Type::ScalarValueParameter,
316                        ],
317                        return_value: Type::NullOrParameter(Box::new(Type::ReleasableParameter {
318                            id: RING_BUFFER_RESERVATION.clone(),
319                            inner: Box::new(Type::MemoryParameter {
320                                size: MemoryParameterSize::Reference { index: 1 },
321                                input: false,
322                                output: false,
323                            }),
324                        })),
325                        invalidate_array_bounds: false,
326                    },
327                },
328            ),
329            (
330                BpfTypeFilter::default(),
331                HelperDefinition {
332                    index: bpf_func_id_BPF_FUNC_ringbuf_submit,
333                    name: "ringbuf_submit",
334                    signature: FunctionSignature {
335                        args: vec![
336                            Type::ReleaseParameter { id: RING_BUFFER_RESERVATION.clone() },
337                            Type::ScalarValueParameter,
338                        ],
339                        return_value: Type::default(),
340                        invalidate_array_bounds: false,
341                    },
342                },
343            ),
344            (
345                BpfTypeFilter::default(),
346                HelperDefinition {
347                    index: bpf_func_id_BPF_FUNC_ringbuf_discard,
348                    name: "ringbuf_discard",
349                    signature: FunctionSignature {
350                        args: vec![
351                            Type::ReleaseParameter { id: RING_BUFFER_RESERVATION.clone() },
352                            Type::ScalarValueParameter,
353                        ],
354                        return_value: Type::default(),
355                        invalidate_array_bounds: false,
356                    },
357                },
358            ),
359            (
360                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
361                HelperDefinition {
362                    index: bpf_func_id_BPF_FUNC_skb_change_proto,
363                    name: "skb_change_proto",
364                    signature: FunctionSignature {
365                        args: vec![
366                            Type::StructParameter { id: SK_BUF_ID.clone() },
367                            Type::ScalarValueParameter,
368                            Type::ScalarValueParameter,
369                        ],
370                        return_value: Type::UNKNOWN_SCALAR,
371                        invalidate_array_bounds: true,
372                    },
373                },
374            ),
375            (
376                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
377                HelperDefinition {
378                    index: bpf_func_id_BPF_FUNC_csum_update,
379                    name: "csum_update",
380                    signature: FunctionSignature {
381                        args: vec![
382                            Type::StructParameter { id: SK_BUF_ID.clone() },
383                            Type::ScalarValueParameter,
384                        ],
385                        return_value: Type::UNKNOWN_SCALAR,
386                        invalidate_array_bounds: false,
387                    },
388                },
389            ),
390            (
391                vec![ProgramType::Kprobe, ProgramType::Tracepoint].into(),
392                HelperDefinition {
393                    index: bpf_func_id_BPF_FUNC_probe_read_str,
394                    name: "probe_read_str",
395                    signature: FunctionSignature {
396                        // TODO(347257215): Implement verifier feature
397                        args: vec![],
398                        return_value: Type::UNKNOWN_SCALAR,
399                        invalidate_array_bounds: false,
400                    },
401                },
402            ),
403            (
404                vec![
405                    ProgramType::CgroupSkb,
406                    ProgramType::SchedAct,
407                    ProgramType::SchedCls,
408                    ProgramType::SocketFilter,
409                    ProgramType::CgroupSock,
410                    ProgramType::CgroupSockAddr,
411                ]
412                .into(),
413                HelperDefinition {
414                    index: bpf_func_id_BPF_FUNC_get_socket_cookie,
415                    name: "get_socket_cookie",
416                    signature: FunctionSignature {
417                        args: vec![Type::ContextParameter { parameter_index: 0 }],
418                        return_value: Type::UNKNOWN_SCALAR,
419                        invalidate_array_bounds: false,
420                    },
421                },
422            ),
423            (
424                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
425                HelperDefinition {
426                    index: bpf_func_id_BPF_FUNC_redirect,
427                    name: "redirect",
428                    signature: FunctionSignature {
429                        args: vec![Type::ScalarValueParameter, Type::ScalarValueParameter],
430                        return_value: Type::UNKNOWN_SCALAR,
431                        invalidate_array_bounds: false,
432                    },
433                },
434            ),
435            (
436                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
437                HelperDefinition {
438                    index: bpf_func_id_BPF_FUNC_skb_adjust_room,
439                    name: "skb_adjust_room",
440                    signature: FunctionSignature {
441                        args: vec![
442                            Type::StructParameter { id: SK_BUF_ID.clone() },
443                            Type::ScalarValueParameter,
444                            Type::ScalarValueParameter,
445                            Type::ScalarValueParameter,
446                        ],
447                        return_value: Type::UNKNOWN_SCALAR,
448                        invalidate_array_bounds: true,
449                    },
450                },
451            ),
452            (
453                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
454                HelperDefinition {
455                    index: bpf_func_id_BPF_FUNC_l3_csum_replace,
456                    name: "l3_csum_replace",
457                    signature: FunctionSignature {
458                        args: vec![
459                            Type::StructParameter { id: SK_BUF_ID.clone() },
460                            Type::ScalarValueParameter,
461                            Type::ScalarValueParameter,
462                            Type::ScalarValueParameter,
463                            Type::ScalarValueParameter,
464                        ],
465                        return_value: Type::UNKNOWN_SCALAR,
466                        invalidate_array_bounds: true,
467                    },
468                },
469            ),
470            (
471                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
472                HelperDefinition {
473                    index: bpf_func_id_BPF_FUNC_l4_csum_replace,
474                    name: "l4_csum_replace",
475                    signature: FunctionSignature {
476                        args: vec![
477                            Type::StructParameter { id: SK_BUF_ID.clone() },
478                            Type::ScalarValueParameter,
479                            Type::ScalarValueParameter,
480                            Type::ScalarValueParameter,
481                            Type::ScalarValueParameter,
482                        ],
483                        return_value: Type::UNKNOWN_SCALAR,
484                        invalidate_array_bounds: true,
485                    },
486                },
487            ),
488            (
489                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
490                HelperDefinition {
491                    index: bpf_func_id_BPF_FUNC_skb_store_bytes,
492                    name: "skb_store_bytes",
493                    signature: FunctionSignature {
494                        args: vec![
495                            Type::StructParameter { id: SK_BUF_ID.clone() },
496                            Type::ScalarValueParameter,
497                            Type::MemoryParameter {
498                                size: MemoryParameterSize::Reference { index: 3 },
499                                input: true,
500                                output: false,
501                            },
502                            Type::ScalarValueParameter,
503                            Type::ScalarValueParameter,
504                        ],
505                        return_value: Type::UNKNOWN_SCALAR,
506                        invalidate_array_bounds: true,
507                    },
508                },
509            ),
510            (
511                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
512                HelperDefinition {
513                    index: bpf_func_id_BPF_FUNC_skb_change_head,
514                    name: "skb_change_head",
515                    signature: FunctionSignature {
516                        args: vec![
517                            Type::StructParameter { id: SK_BUF_ID.clone() },
518                            Type::ScalarValueParameter,
519                            Type::ScalarValueParameter,
520                        ],
521                        return_value: Type::UNKNOWN_SCALAR,
522                        invalidate_array_bounds: true,
523                    },
524                },
525            ),
526            (
527                vec![
528                    ProgramType::CgroupSkb,
529                    ProgramType::SchedAct,
530                    ProgramType::SchedCls,
531                    ProgramType::SocketFilter,
532                ]
533                .into(),
534                HelperDefinition {
535                    index: bpf_func_id_BPF_FUNC_skb_load_bytes,
536                    name: "skb_load_bytes",
537                    signature: FunctionSignature {
538                        args: vec![
539                            Type::StructParameter { id: SK_BUF_ID.clone() },
540                            Type::ScalarValueParameter,
541                            Type::MemoryParameter {
542                                size: MemoryParameterSize::Reference { index: 3 },
543                                input: false,
544                                output: true,
545                            },
546                            Type::ScalarValueParameter,
547                        ],
548                        return_value: Type::UNKNOWN_SCALAR,
549                        invalidate_array_bounds: false,
550                    },
551                },
552            ),
553            (
554                vec![
555                    ProgramType::CgroupSkb,
556                    ProgramType::SchedAct,
557                    ProgramType::SchedCls,
558                    ProgramType::SocketFilter,
559                ]
560                .into(),
561                HelperDefinition {
562                    index: bpf_func_id_BPF_FUNC_skb_load_bytes_relative,
563                    name: "skb_load_bytes_relative",
564                    signature: FunctionSignature {
565                        args: vec![
566                            Type::StructParameter { id: SK_BUF_ID.clone() },
567                            Type::ScalarValueParameter,
568                            Type::MemoryParameter {
569                                size: MemoryParameterSize::Reference { index: 3 },
570                                input: false,
571                                output: true,
572                            },
573                            Type::ScalarValueParameter,
574                            Type::ScalarValueParameter,
575                        ],
576                        return_value: Type::UNKNOWN_SCALAR,
577                        invalidate_array_bounds: false,
578                    },
579                },
580            ),
581            (
582                BpfTypeFilter::default(),
583                HelperDefinition {
584                    index: bpf_func_id_BPF_FUNC_ktime_get_boot_ns,
585                    name: "ktime_get_boot_ns",
586                    signature: FunctionSignature {
587                        args: vec![],
588                        return_value: Type::UNKNOWN_SCALAR,
589                        invalidate_array_bounds: false,
590                    },
591                },
592            ),
593            (
594                BpfTypeFilter::default(),
595                HelperDefinition {
596                    index: bpf_func_id_BPF_FUNC_ktime_get_coarse_ns,
597                    name: "ktime_get_coarse_ns",
598                    signature: FunctionSignature {
599                        args: vec![],
600                        return_value: Type::UNKNOWN_SCALAR,
601                        invalidate_array_bounds: false,
602                    },
603                },
604            ),
605            (
606                vec![
607                    ProgramType::CgroupSkb,
608                    ProgramType::CgroupSock,
609                    ProgramType::CgroupSockopt,
610                    ProgramType::CgroupSockAddr,
611                ]
612                .into(),
613                HelperDefinition {
614                    index: bpf_func_id_BPF_FUNC_sk_storage_get,
615                    name: "sk_storage_get",
616                    signature: FunctionSignature {
617                        args: vec![
618                            Type::ConstPtrToMapParameter {
619                                filter: MapTypeFilter::AllowList(&[
620                                    bpf_map_type_BPF_MAP_TYPE_SK_STORAGE,
621                                ]),
622                            },
623                            Type::StructParameter { id: BPF_SOCK_ID.clone() },
624                            Type::NullOrParameter(Box::new(Type::MapValueParameter {
625                                map_ptr_index: 0,
626                            })),
627                            Type::ScalarValueParameter,
628                        ],
629                        return_value: Type::NullOrParameter(Box::new(Type::MapValueParameter {
630                            map_ptr_index: 0,
631                        })),
632                        invalidate_array_bounds: false,
633                    },
634                },
635            ),
636            (
637                BpfTypeFilter::default(),
638                HelperDefinition {
639                    index: bpf_func_id_BPF_FUNC_get_smp_processor_id,
640                    name: "get_smp_processor_id",
641                    signature: FunctionSignature {
642                        args: vec![],
643                        return_value: Type::UNKNOWN_SCALAR,
644                        invalidate_array_bounds: false,
645                    },
646                },
647            ),
648            (
649                vec![ProgramType::CgroupSkb, ProgramType::SchedAct, ProgramType::SchedCls].into(),
650                HelperDefinition {
651                    index: bpf_func_id_BPF_FUNC_sk_fullsock,
652                    name: "sk_fullsock",
653                    signature: FunctionSignature {
654                        args: vec![Type::StructParameter { id: BPF_SOCK_ID.clone() }],
655                        return_value: Type::NullOrParameter(Box::new(ptr_to_mem_type::<bpf_sock>(
656                            BPF_SOCK_ID.clone(),
657                        ))),
658                        invalidate_array_bounds: false,
659                    },
660                },
661            ),
662            (
663                vec![
664                    ProgramType::CgroupDevice,
665                    ProgramType::CgroupSockopt,
666                    ProgramType::CgroupSysctl,
667                ]
668                .into(),
669                HelperDefinition {
670                    index: bpf_func_id_BPF_FUNC_set_retval,
671                    name: "set_retval",
672                    signature: FunctionSignature {
673                        args: vec![Type::ScalarValueParameter],
674                        return_value: Type::UNKNOWN_SCALAR,
675                        invalidate_array_bounds: false,
676                    },
677                },
678            ),
679            (
680                vec![
681                    ProgramType::CgroupDevice,
682                    ProgramType::CgroupSockopt,
683                    ProgramType::CgroupSysctl,
684                ]
685                .into(),
686                HelperDefinition {
687                    index: bpf_func_id_BPF_FUNC_get_retval,
688                    name: "get_retval",
689                    signature: FunctionSignature {
690                        args: vec![],
691                        return_value: Type::UNKNOWN_SCALAR,
692                        invalidate_array_bounds: false,
693                    },
694                },
695            ),
696            (
697                // Note that bpf_sk_lookup_tcp should also be available to CgroupAddr and Xdp
698                // programs, but those use different type for the first context parameter.
699                vec![
700                    ProgramType::CgroupSkb,
701                    ProgramType::SchedAct,
702                    ProgramType::SchedCls,
703                    ProgramType::SkSkb,
704                ]
705                .into(),
706                HelperDefinition {
707                    index: bpf_func_id_BPF_FUNC_sk_lookup_tcp,
708                    name: "sk_lookup_tcp",
709                    signature: FunctionSignature {
710                        args: vec![
711                            Type::StructParameter { id: SK_BUF_ID.clone() },
712                            Type::MemoryParameter {
713                                size: MemoryParameterSize::Reference { index: 2 },
714                                input: true,
715                                output: false,
716                            },
717                            Type::ScalarValueParameter,
718                            Type::ScalarValueParameter,
719                            Type::ScalarValueParameter,
720                        ],
721                        return_value: Type::NullOrParameter(Box::new(Type::ReleasableParameter {
722                            id: RELEASABLE_BPF_SOCK_PTR.clone(),
723                            inner: Box::new(BPF_SOCK_TYPE.clone()),
724                        })),
725                        invalidate_array_bounds: false,
726                    },
727                },
728            ),
729            (
730                // Note that bpf_sk_lookup_udp should also be available to CgroupAddr and Xdp
731                // programs, but those use different type for the first context parameter.
732                vec![
733                    ProgramType::CgroupSkb,
734                    ProgramType::SchedAct,
735                    ProgramType::SchedCls,
736                    ProgramType::SkSkb,
737                ]
738                .into(),
739                HelperDefinition {
740                    index: bpf_func_id_BPF_FUNC_sk_lookup_udp,
741                    name: "sk_lookup_udp",
742                    signature: FunctionSignature {
743                        args: vec![
744                            Type::StructParameter { id: SK_BUF_ID.clone() },
745                            Type::MemoryParameter {
746                                size: MemoryParameterSize::Reference { index: 2 },
747                                input: true,
748                                output: false,
749                            },
750                            Type::ScalarValueParameter,
751                            Type::ScalarValueParameter,
752                            Type::ScalarValueParameter,
753                        ],
754                        return_value: Type::NullOrParameter(Box::new(Type::ReleasableParameter {
755                            id: RELEASABLE_BPF_SOCK_PTR.clone(),
756                            inner: Box::new(BPF_SOCK_TYPE.clone()),
757                        })),
758                        invalidate_array_bounds: false,
759                    },
760                },
761            ),
762            (
763                vec![
764                    ProgramType::CgroupSkb,
765                    ProgramType::CgroupSockAddr,
766                    ProgramType::SchedAct,
767                    ProgramType::SchedCls,
768                    ProgramType::SkSkb,
769                    ProgramType::Xdp,
770                ]
771                .into(),
772                HelperDefinition {
773                    index: bpf_func_id_BPF_FUNC_sk_release,
774                    name: "sk_release",
775                    signature: FunctionSignature {
776                        args: vec![Type::ReleaseParameter { id: RELEASABLE_BPF_SOCK_PTR.clone() }],
777                        return_value: Type::UNKNOWN_SCALAR,
778                        invalidate_array_bounds: false,
779                    },
780                },
781            ),
782            (
783                vec![
784                    ProgramType::CgroupSkb,
785                    ProgramType::CgroupSock,
786                    ProgramType::CgroupSockopt,
787                    ProgramType::CgroupSockAddr,
788                    ProgramType::SchedAct,
789                    ProgramType::SchedCls,
790                    ProgramType::SkMsg,
791                    ProgramType::SocketFilter,
792                    ProgramType::SockOps,
793                ]
794                .into(),
795                HelperDefinition {
796                    index: bpf_func_id_BPF_FUNC_get_netns_cookie,
797                    name: "bpf_get_netns_cookie",
798                    signature: FunctionSignature {
799                        args: vec![Type::NullOrParameter(Box::new(Type::ContextParameter {
800                            parameter_index: 0,
801                        }))],
802                        return_value: Type::UNKNOWN_SCALAR,
803                        invalidate_array_bounds: false,
804                    },
805                },
806            ),
807        ]
808    });
809
810/// A type of a struct that may be passed to eBPF programs.
811#[derive(Copy, Clone)]
812pub enum StructId {
813    SkBuff = 1,
814    XdpMd = 2,
815    BpfUserPtRegs = 3,
816    BpfSock = 4,
817    BpfSockOpt = 5,
818    BpfSockAddr = 6,
819    BpfFuse = 7,
820}
821
822impl StructId {
823    pub const fn as_memory_id(self) -> MemoryId {
824        MemoryId::from_raw(self as u64)
825    }
826}
827
828impl From<StructId> for febpf::StructId {
829    fn from(value: StructId) -> Self {
830        match value {
831            StructId::SkBuff => febpf::StructId::SkBuff,
832            StructId::XdpMd => febpf::StructId::XdpMd,
833            StructId::BpfUserPtRegs => febpf::StructId::BpfUserPtRegs,
834            StructId::BpfSock => febpf::StructId::BpfSock,
835            StructId::BpfSockOpt => febpf::StructId::BpfSockOpt,
836            StructId::BpfSockAddr => febpf::StructId::BpfSockAddr,
837            StructId::BpfFuse => febpf::StructId::BpfFuse,
838        }
839    }
840}
841
842impl TryFrom<&MemoryId> for StructId {
843    type Error = ();
844
845    fn try_from(value: &MemoryId) -> Result<Self, Self::Error> {
846        if *value == StructId::SkBuff.as_memory_id() {
847            Ok(StructId::SkBuff)
848        } else if *value == StructId::XdpMd.as_memory_id() {
849            Ok(StructId::XdpMd)
850        } else if *value == StructId::BpfUserPtRegs.as_memory_id() {
851            Ok(StructId::BpfUserPtRegs)
852        } else if *value == StructId::BpfSock.as_memory_id() {
853            Ok(StructId::BpfSock)
854        } else if *value == StructId::BpfSockOpt.as_memory_id() {
855            Ok(StructId::BpfSockOpt)
856        } else if *value == StructId::BpfSockAddr.as_memory_id() {
857            Ok(StructId::BpfSockAddr)
858        } else if *value == StructId::BpfFuse.as_memory_id() {
859            Ok(StructId::BpfFuse)
860        } else {
861            Err(())
862        }
863    }
864}
865
866impl From<febpf::StructId> for StructId {
867    fn from(value: febpf::StructId) -> Self {
868        match value {
869            febpf::StructId::SkBuff => StructId::SkBuff,
870            febpf::StructId::XdpMd => StructId::XdpMd,
871            febpf::StructId::BpfUserPtRegs => StructId::BpfUserPtRegs,
872            febpf::StructId::BpfSock => StructId::BpfSock,
873            febpf::StructId::BpfSockOpt => StructId::BpfSockOpt,
874            febpf::StructId::BpfSockAddr => StructId::BpfSockAddr,
875            febpf::StructId::BpfFuse => StructId::BpfFuse,
876            febpf::StructId::__SourceBreaking { unknown_ordinal } => {
877                panic!("Invalid struct id: {}", unknown_ordinal)
878            }
879        }
880    }
881}
882
883fn scalar_field(offset: usize, size: usize) -> FieldDescriptor {
884    FieldDescriptor { offset, field_type: FieldType::Scalar { size } }
885}
886
887fn scalar_range(offset: usize, end_offset: usize) -> FieldDescriptor {
888    FieldDescriptor { offset, field_type: FieldType::Scalar { size: end_offset - offset } }
889}
890
891fn scalar_mut_range(offset: usize, end_offset: usize) -> FieldDescriptor {
892    FieldDescriptor { offset, field_type: FieldType::MutableScalar { size: end_offset - offset } }
893}
894
895fn scalar_u32_field(offset: usize) -> FieldDescriptor {
896    FieldDescriptor { offset, field_type: FieldType::Scalar { size: std::mem::size_of::<u32>() } }
897}
898
899fn scalar_u32_mut_field(offset: usize) -> FieldDescriptor {
900    FieldDescriptor {
901        offset,
902        field_type: FieldType::MutableScalar { size: std::mem::size_of::<u32>() },
903    }
904}
905
906fn scalar_u64_field(offset: usize) -> FieldDescriptor {
907    FieldDescriptor { offset, field_type: FieldType::Scalar { size: std::mem::size_of::<u64>() } }
908}
909
910fn array_start_field(offset: usize, id: MemoryId) -> FieldDescriptor {
911    FieldDescriptor { offset, field_type: FieldType::PtrToArray { id, is_32_bit: false } }
912}
913
914fn array_end_field(offset: usize, id: MemoryId) -> FieldDescriptor {
915    FieldDescriptor { offset, field_type: FieldType::PtrToEndArray { id, is_32_bit: false } }
916}
917
918fn array_start_32_field(offset: usize, id: MemoryId) -> FieldDescriptor {
919    FieldDescriptor { offset, field_type: FieldType::PtrToArray { id, is_32_bit: true } }
920}
921
922fn array_end_32_field(offset: usize, id: MemoryId) -> FieldDescriptor {
923    FieldDescriptor { offset, field_type: FieldType::PtrToEndArray { id, is_32_bit: true } }
924}
925
926fn ptr_to_mem_field<T: IntoBytes>(offset: usize, id: MemoryId) -> FieldDescriptor {
927    FieldDescriptor {
928        offset,
929        field_type: FieldType::PtrToMemory {
930            id,
931            buffer_size: std::mem::size_of::<T>(),
932            is_32_bit: false,
933        },
934    }
935}
936
937fn nullable_ptr_to_mem_field<T: IntoBytes>(offset: usize, id: MemoryId) -> FieldDescriptor {
938    FieldDescriptor {
939        offset,
940        field_type: FieldType::NullablePtrToMemory {
941            is_32_bit: false,
942            id,
943            buffer_size: std::mem::size_of::<T>(),
944        },
945    }
946}
947
948fn ptr_to_struct_type(id: MemoryId, fields: Vec<FieldDescriptor>) -> Type {
949    Type::PtrToStruct { id, offset: 0.into(), descriptor: Arc::new(StructDescriptor { fields }) }
950}
951
952fn ptr_to_mem_type<T: IntoBytes>(id: MemoryId) -> Type {
953    Type::PtrToMemory { id, offset: 0.into(), buffer_size: std::mem::size_of::<T>() as u64 }
954}
955
956static RING_BUFFER_RESERVATION: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
957
958// Id for the value returned from `bpf_sk_lookup_xxx` helpers. It has to be
959// released by calling `bpf_sk_release`.
960static RELEASABLE_BPF_SOCK_PTR: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
961
962pub static SK_BUF_ID: MemoryId = StructId::SkBuff.as_memory_id();
963
964/// Type for the `__sk_buff` passed to `BPF_PROG_TYPE_SOCKET_FILTER` programs.
965pub static SOCKET_FILTER_SK_BUF_TYPE: LazyLock<Type> = LazyLock::new(|| {
966    ptr_to_struct_type(
967        SK_BUF_ID.clone(),
968        vec![
969            // All fields from the start of `__sk_buff` to `cb` are read-only scalars.
970            scalar_range(0, offset_of!(__sk_buff, cb)),
971            // `cb` is a mutable array.
972            scalar_mut_range(offset_of!(__sk_buff, cb), offset_of!(__sk_buff, hash)),
973            scalar_u32_field(offset_of!(__sk_buff, hash)),
974            scalar_u32_field(offset_of!(__sk_buff, napi_id)),
975            scalar_u32_field(offset_of!(__sk_buff, tstamp)),
976            scalar_u32_field(offset_of!(__sk_buff, gso_segs)),
977            scalar_u32_field(offset_of!(__sk_buff, gso_size)),
978        ],
979    )
980});
981pub static SOCKET_FILTER_ARGS: LazyLock<Vec<Type>> =
982    LazyLock::new(|| vec![SOCKET_FILTER_SK_BUF_TYPE.clone()]);
983
984/// Type for the `__sk_buff` passed to `BPF_PROG_TYPE_SCHED_CLS` and
985/// `BPF_PROG_TYPE_SCHED_ACT` programs.
986pub static SCHED_ARG_TYPE: LazyLock<Type> = LazyLock::new(|| {
987    let data_id = MemoryId::new();
988    ptr_to_struct_type(
989        SK_BUF_ID.clone(),
990        vec![
991            // All fields from the start of `__sk_buff` to `cb` are read-only scalars, except mark
992            // that is read-write.
993            scalar_range(0, offset_of!(__sk_buff, mark)),
994            scalar_u32_mut_field(offset_of!(__sk_buff, mark)),
995            scalar_range(offset_of!(__sk_buff, queue_mapping), offset_of!(__sk_buff, cb)),
996            // `cb` is a mutable array.
997            scalar_mut_range(offset_of!(__sk_buff, cb), offset_of!(__sk_buff, hash)),
998            scalar_u32_field(offset_of!(__sk_buff, hash)),
999            scalar_u32_field(offset_of!(__sk_buff, tc_classid)),
1000            array_start_32_field(offset_of!(__sk_buff, data), data_id.clone()),
1001            array_end_32_field(offset_of!(__sk_buff, data_end), data_id),
1002            scalar_u32_field(offset_of!(__sk_buff, napi_id)),
1003            scalar_u32_field(offset_of!(__sk_buff, data_meta)),
1004            scalar_range(offset_of!(__sk_buff, tstamp), size_of::<__sk_buff>()),
1005        ],
1006    )
1007});
1008pub static SCHED_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![SCHED_ARG_TYPE.clone()]);
1009
1010/// Type for the `__sk_buff` passed to `BPF_PROG_TYPE_CGROUP_SKB` programs.
1011pub static CGROUP_SKB_SK_BUF_TYPE: LazyLock<Type> = LazyLock::new(|| {
1012    let data_id = MemoryId::new();
1013    assert!(offset_of!(__sk_buff, __bindgen_anon_2) == 168);
1014    ptr_to_struct_type(
1015        SK_BUF_ID.clone(),
1016        vec![
1017            // All fields from the start of `__sk_buff` to `cb` are read-only scalars, except mark
1018            // that is read-write.
1019            scalar_range(0, offset_of!(__sk_buff, mark)),
1020            scalar_u32_mut_field(offset_of!(__sk_buff, mark)),
1021            scalar_range(offset_of!(__sk_buff, queue_mapping), offset_of!(__sk_buff, cb)),
1022            // `cb` is a mutable array.
1023            scalar_mut_range(offset_of!(__sk_buff, cb), offset_of!(__sk_buff, hash)),
1024            scalar_u32_field(offset_of!(__sk_buff, hash)),
1025            array_start_32_field(offset_of!(__sk_buff, data), data_id.clone()),
1026            array_end_32_field(offset_of!(__sk_buff, data_end), data_id),
1027            scalar_range(offset_of!(__sk_buff, napi_id), offset_of!(__sk_buff, data_meta)),
1028            scalar_u64_field(offset_of!(__sk_buff, tstamp)),
1029            scalar_u32_field(offset_of!(__sk_buff, gso_segs)),
1030            // `sk` field
1031            nullable_ptr_to_mem_field::<bpf_sock>(
1032                offset_of!(__sk_buff, __bindgen_anon_2),
1033                BPF_SOCK_ID.clone(),
1034            ),
1035            scalar_u32_field(offset_of!(__sk_buff, gso_size)),
1036            scalar_u64_field(offset_of!(__sk_buff, hwtstamp)),
1037        ],
1038    )
1039});
1040pub static CGROUP_SKB_ARGS: LazyLock<Vec<Type>> =
1041    LazyLock::new(|| vec![CGROUP_SKB_SK_BUF_TYPE.clone()]);
1042
1043static XDP_MD_ID: MemoryId = StructId::XdpMd.as_memory_id();
1044static XDP_MD_TYPE: LazyLock<Type> = LazyLock::new(|| {
1045    let data_id = MemoryId::new();
1046
1047    ptr_to_struct_type(
1048        XDP_MD_ID.clone(),
1049        vec![
1050            array_start_32_field(offset_of!(xdp_md, data), data_id.clone()),
1051            array_end_32_field(offset_of!(xdp_md, data_end), data_id),
1052            // All fields starting from `data_meta` are readable.
1053            {
1054                let data_meta_offset = offset_of!(xdp_md, data_meta);
1055                scalar_field(data_meta_offset, std::mem::size_of::<xdp_md>() - data_meta_offset)
1056            },
1057        ],
1058    )
1059});
1060static XDP_MD_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![XDP_MD_TYPE.clone()]);
1061
1062pub static BPF_USER_PT_REGS_T_ID: MemoryId = StructId::BpfUserPtRegs.as_memory_id();
1063pub static BPF_USER_PT_REGS_T_ARGS: LazyLock<Vec<Type>> =
1064    LazyLock::new(|| vec![ptr_to_mem_type::<bpf_user_pt_regs_t>(BPF_USER_PT_REGS_T_ID.clone())]);
1065
1066pub static BPF_SOCK_ID: MemoryId = StructId::BpfSock.as_memory_id();
1067pub static BPF_SOCK_TYPE: LazyLock<Type> =
1068    LazyLock::new(|| ptr_to_mem_type::<bpf_sock>(BPF_SOCK_ID.clone()));
1069pub static BPF_SOCK_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![BPF_SOCK_TYPE.clone()]);
1070
1071pub static BPF_SOCKOPT_ID: MemoryId = StructId::BpfSockOpt.as_memory_id();
1072pub static BPF_SOCKOPT_TYPE: LazyLock<Type> = LazyLock::new(|| {
1073    let optval_id = MemoryId::new();
1074    ptr_to_struct_type(
1075        BPF_SOCKOPT_ID.clone(),
1076        vec![
1077            // sk
1078            ptr_to_mem_field::<bpf_sock>(
1079                offset_of!(bpf_sockopt, __bindgen_anon_1),
1080                BPF_SOCK_ID.clone(),
1081            ),
1082            // optval
1083            array_start_field(offset_of!(bpf_sockopt, __bindgen_anon_2), optval_id.clone()),
1084            // optval_end
1085            array_end_field(offset_of!(bpf_sockopt, __bindgen_anon_3), optval_id),
1086            scalar_u32_field(offset_of!(bpf_sockopt, level)),
1087            scalar_u32_mut_field(offset_of!(bpf_sockopt, optname)),
1088            scalar_u32_mut_field(offset_of!(bpf_sockopt, optlen)),
1089            scalar_u32_mut_field(offset_of!(bpf_sockopt, retval)),
1090        ],
1091    )
1092});
1093pub static BPF_SOCKOPT_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![BPF_SOCKOPT_TYPE.clone()]);
1094
1095// Verifier allows access only to some fields of the `bfp_sock_addr` struct
1096// depending on the `expected_attach_type` passed when the program is loaded.
1097// The INET4 and INET6 versions defined below should be used by the verifier
1098// for INET4 and INET6 attachments. `BPF_SOCK_ADDR_TYPE` contains all fields
1099// from that struct. It's used by the `ProgramArgument` implementation for
1100// the struct. This allows to share the `EbpfProgramContext` for all programs
1101// that take `bpf_sock_addr`. Linkers considers `BPF_SOCK_ADDR_TYPE` as is
1102// a subtype of both INET4 and INET6 versions.
1103pub static BPF_SOCK_ADDR_ID: MemoryId = StructId::BpfSockAddr.as_memory_id();
1104pub static BPF_SOCK_ADDR_TYPE: LazyLock<Type> = LazyLock::new(|| {
1105    ptr_to_struct_type(
1106        BPF_SOCK_ADDR_ID.clone(),
1107        vec![
1108            scalar_u32_field(offset_of!(bpf_sock_addr, user_family)),
1109            scalar_u32_field(offset_of!(bpf_sock_addr, user_ip4)),
1110            scalar_field(offset_of!(bpf_sock_addr, user_ip6), 16),
1111            scalar_u32_field(offset_of!(bpf_sock_addr, user_port)),
1112            scalar_u32_field(offset_of!(bpf_sock_addr, family)),
1113            scalar_u32_field(offset_of!(bpf_sock_addr, type_)),
1114            scalar_u32_field(offset_of!(bpf_sock_addr, protocol)),
1115            scalar_u32_field(offset_of!(bpf_sock_addr, msg_src_ip4)),
1116            scalar_field(offset_of!(bpf_sock_addr, msg_src_ip6), 16),
1117            // sk
1118            ptr_to_mem_field::<bpf_sock>(
1119                offset_of!(bpf_sock_addr, __bindgen_anon_1),
1120                BPF_SOCK_ID.clone(),
1121            ),
1122        ],
1123    )
1124});
1125
1126pub static BPF_SOCK_ADDR_INET4_TYPE: LazyLock<Type> = LazyLock::new(|| {
1127    ptr_to_struct_type(
1128        BPF_SOCK_ADDR_ID.clone(),
1129        vec![
1130            scalar_u32_field(offset_of!(bpf_sock_addr, user_family)),
1131            scalar_u32_field(offset_of!(bpf_sock_addr, user_ip4)),
1132            scalar_u32_field(offset_of!(bpf_sock_addr, user_port)),
1133            scalar_u32_field(offset_of!(bpf_sock_addr, family)),
1134            scalar_u32_field(offset_of!(bpf_sock_addr, type_)),
1135            scalar_u32_field(offset_of!(bpf_sock_addr, protocol)),
1136            // sk
1137            ptr_to_mem_field::<bpf_sock>(
1138                offset_of!(bpf_sock_addr, __bindgen_anon_1),
1139                BPF_SOCK_ID.clone(),
1140            ),
1141        ],
1142    )
1143});
1144pub static BPF_SOCK_ADDR_INET4_ARGS: LazyLock<Vec<Type>> =
1145    LazyLock::new(|| vec![BPF_SOCK_ADDR_INET4_TYPE.clone()]);
1146
1147pub static BPF_SOCK_ADDR_INET6_TYPE: LazyLock<Type> = LazyLock::new(|| {
1148    ptr_to_struct_type(
1149        BPF_SOCK_ADDR_ID.clone(),
1150        vec![
1151            scalar_u32_field(offset_of!(bpf_sock_addr, user_family)),
1152            scalar_field(offset_of!(bpf_sock_addr, user_ip6), 16),
1153            scalar_u32_field(offset_of!(bpf_sock_addr, user_port)),
1154            scalar_u32_field(offset_of!(bpf_sock_addr, family)),
1155            scalar_u32_field(offset_of!(bpf_sock_addr, type_)),
1156            scalar_u32_field(offset_of!(bpf_sock_addr, protocol)),
1157            // sk
1158            ptr_to_mem_field::<bpf_sock>(
1159                offset_of!(bpf_sock_addr, __bindgen_anon_1),
1160                BPF_SOCK_ID.clone(),
1161            ),
1162        ],
1163    )
1164});
1165pub static BPF_SOCK_ADDR_INET6_ARGS: LazyLock<Vec<Type>> =
1166    LazyLock::new(|| vec![BPF_SOCK_ADDR_INET6_TYPE.clone()]);
1167
1168static BPF_FUSE_ID: MemoryId = StructId::BpfFuse.as_memory_id();
1169static BPF_FUSE_TYPE: LazyLock<Type> = LazyLock::new(|| {
1170    ptr_to_struct_type(
1171        BPF_FUSE_ID.clone(),
1172        vec![
1173            scalar_field(0, offset_of!(fuse_bpf_args, out_args)),
1174            ptr_to_mem_field::<fuse_entry_out>(
1175                offset_of!(fuse_bpf_args, out_args) + offset_of!(fuse_bpf_arg, value),
1176                MemoryId::new(),
1177            ),
1178            ptr_to_mem_field::<fuse_entry_bpf_out>(
1179                offset_of!(fuse_bpf_args, out_args)
1180                    + std::mem::size_of::<fuse_bpf_arg>()
1181                    + offset_of!(fuse_bpf_arg, value),
1182                MemoryId::new(),
1183            ),
1184        ],
1185    )
1186});
1187static BPF_FUSE_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![BPF_FUSE_TYPE.clone()]);
1188
1189#[repr(C)]
1190#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
1191struct TraceEntry {
1192    type_: u16,
1193    flags: u8,
1194    preemp_count: u8,
1195    pid: u32,
1196}
1197
1198#[repr(C)]
1199#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
1200struct TraceEvent {
1201    trace_entry: TraceEntry,
1202    id: u64,
1203    // This is defined a being big enough for all expected tracepoint. It is not clear how the
1204    // verifier can know which tracepoint is targeted when the program is loaded. Instead, this
1205    // array will be big enough, and will be filled with 0 when running a given program.
1206    args: [u64; 16],
1207}
1208
1209#[repr(C)]
1210#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
1211struct RawTraceEvent {
1212    // This is defined a being big enough for all expected tracepoint. It is not clear how the
1213    // verifier can know which tracepoint is targeted when the program is loaded. Instead, this
1214    // array will be big enough, and will be filled with 0 when running a given program.
1215    args: [u64; 2],
1216}
1217
1218static BPF_TRACEPOINT_ID: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
1219static BPF_TRACEPOINT_ARGS: LazyLock<Vec<Type>> =
1220    LazyLock::new(|| vec![ptr_to_mem_type::<TraceEvent>(BPF_TRACEPOINT_ID.clone())]);
1221
1222static BPF_RAW_TRACEPOINT_ID: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
1223static BPF_RAW_TRACEPOINT_ARGS: LazyLock<Vec<Type>> =
1224    LazyLock::new(|| vec![ptr_to_mem_type::<RawTraceEvent>(BPF_RAW_TRACEPOINT_ID.clone())]);
1225
1226/// The different type of BPF programs.
1227#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1228pub enum ProgramType {
1229    CgroupDevice,
1230    CgroupSkb,
1231    CgroupSock,
1232    CgroupSockAddr,
1233    CgroupSockopt,
1234    CgroupSysctl,
1235    Ext,
1236    FlowDissector,
1237    Kprobe,
1238    LircMode2,
1239    Lsm,
1240    LwtIn,
1241    LwtOut,
1242    LwtSeg6Local,
1243    LwtXmit,
1244    Netfilter,
1245    PerfEvent,
1246    RawTracepoint,
1247    RawTracepointWritable,
1248    SchedAct,
1249    SchedCls,
1250    SkLookup,
1251    SkMsg,
1252    SkReuseport,
1253    SkSkb,
1254    SocketFilter,
1255    SockOps,
1256    StructOps,
1257    Syscall,
1258    Tracepoint,
1259    Tracing,
1260    Unspec,
1261    Xdp,
1262    /// Custom id for Fuse
1263    Fuse,
1264}
1265
1266#[derive(thiserror::Error, Debug, PartialEq, Eq)]
1267pub enum EbpfApiError {
1268    #[error("Invalid program type: 0x{0:x}")]
1269    InvalidProgramType(u32),
1270
1271    #[error("Unsupported program type: {0:?}")]
1272    UnsupportedProgramType(ProgramType),
1273
1274    #[error("Invalid expected_attach_type: 0x{0:?}")]
1275    InvalidExpectedAttachType(AttachType),
1276}
1277
1278impl TryFrom<u32> for ProgramType {
1279    type Error = EbpfApiError;
1280
1281    fn try_from(program_type: u32) -> Result<Self, Self::Error> {
1282        match program_type {
1283            #![allow(non_upper_case_globals)]
1284            bpf_prog_type_BPF_PROG_TYPE_CGROUP_DEVICE => Ok(Self::CgroupDevice),
1285            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SKB => Ok(Self::CgroupSkb),
1286            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK => Ok(Self::CgroupSock),
1287            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK_ADDR => Ok(Self::CgroupSockAddr),
1288            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCKOPT => Ok(Self::CgroupSockopt),
1289            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SYSCTL => Ok(Self::CgroupSysctl),
1290            bpf_prog_type_BPF_PROG_TYPE_EXT => Ok(Self::Ext),
1291            bpf_prog_type_BPF_PROG_TYPE_FLOW_DISSECTOR => Ok(Self::FlowDissector),
1292            bpf_prog_type_BPF_PROG_TYPE_KPROBE => Ok(Self::Kprobe),
1293            bpf_prog_type_BPF_PROG_TYPE_LIRC_MODE2 => Ok(Self::LircMode2),
1294            bpf_prog_type_BPF_PROG_TYPE_LSM => Ok(Self::Lsm),
1295            bpf_prog_type_BPF_PROG_TYPE_LWT_IN => Ok(Self::LwtIn),
1296            bpf_prog_type_BPF_PROG_TYPE_LWT_OUT => Ok(Self::LwtOut),
1297            bpf_prog_type_BPF_PROG_TYPE_LWT_SEG6LOCAL => Ok(Self::LwtSeg6Local),
1298            bpf_prog_type_BPF_PROG_TYPE_LWT_XMIT => Ok(Self::LwtXmit),
1299            bpf_prog_type_BPF_PROG_TYPE_NETFILTER => Ok(Self::Netfilter),
1300            bpf_prog_type_BPF_PROG_TYPE_PERF_EVENT => Ok(Self::PerfEvent),
1301            bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT => Ok(Self::RawTracepoint),
1302            bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE => Ok(Self::RawTracepointWritable),
1303            bpf_prog_type_BPF_PROG_TYPE_SCHED_ACT => Ok(Self::SchedAct),
1304            bpf_prog_type_BPF_PROG_TYPE_SCHED_CLS => Ok(Self::SchedCls),
1305            bpf_prog_type_BPF_PROG_TYPE_SK_LOOKUP => Ok(Self::SkLookup),
1306            bpf_prog_type_BPF_PROG_TYPE_SK_MSG => Ok(Self::SkMsg),
1307            bpf_prog_type_BPF_PROG_TYPE_SK_REUSEPORT => Ok(Self::SkReuseport),
1308            bpf_prog_type_BPF_PROG_TYPE_SK_SKB => Ok(Self::SkSkb),
1309            bpf_prog_type_BPF_PROG_TYPE_SOCK_OPS => Ok(Self::SockOps),
1310            bpf_prog_type_BPF_PROG_TYPE_SOCKET_FILTER => Ok(Self::SocketFilter),
1311            bpf_prog_type_BPF_PROG_TYPE_STRUCT_OPS => Ok(Self::StructOps),
1312            bpf_prog_type_BPF_PROG_TYPE_SYSCALL => Ok(Self::Syscall),
1313            bpf_prog_type_BPF_PROG_TYPE_TRACEPOINT => Ok(Self::Tracepoint),
1314            bpf_prog_type_BPF_PROG_TYPE_TRACING => Ok(Self::Tracing),
1315            bpf_prog_type_BPF_PROG_TYPE_UNSPEC => Ok(Self::Unspec),
1316            bpf_prog_type_BPF_PROG_TYPE_XDP => Ok(Self::Xdp),
1317            BPF_PROG_TYPE_FUSE => Ok(Self::Fuse),
1318            program_type @ _ => Err(EbpfApiError::InvalidProgramType(program_type)),
1319        }
1320    }
1321}
1322
1323impl From<ProgramType> for u32 {
1324    fn from(program_type: ProgramType) -> u32 {
1325        match program_type {
1326            ProgramType::CgroupDevice => bpf_prog_type_BPF_PROG_TYPE_CGROUP_DEVICE,
1327            ProgramType::CgroupSkb => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SKB,
1328            ProgramType::CgroupSock => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK,
1329            ProgramType::CgroupSockAddr => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
1330            ProgramType::CgroupSockopt => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCKOPT,
1331            ProgramType::CgroupSysctl => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SYSCTL,
1332            ProgramType::Ext => bpf_prog_type_BPF_PROG_TYPE_EXT,
1333            ProgramType::FlowDissector => bpf_prog_type_BPF_PROG_TYPE_FLOW_DISSECTOR,
1334            ProgramType::Kprobe => bpf_prog_type_BPF_PROG_TYPE_KPROBE,
1335            ProgramType::LircMode2 => bpf_prog_type_BPF_PROG_TYPE_LIRC_MODE2,
1336            ProgramType::Lsm => bpf_prog_type_BPF_PROG_TYPE_LSM,
1337            ProgramType::LwtIn => bpf_prog_type_BPF_PROG_TYPE_LWT_IN,
1338            ProgramType::LwtOut => bpf_prog_type_BPF_PROG_TYPE_LWT_OUT,
1339            ProgramType::LwtSeg6Local => bpf_prog_type_BPF_PROG_TYPE_LWT_SEG6LOCAL,
1340            ProgramType::LwtXmit => bpf_prog_type_BPF_PROG_TYPE_LWT_XMIT,
1341            ProgramType::Netfilter => bpf_prog_type_BPF_PROG_TYPE_NETFILTER,
1342            ProgramType::PerfEvent => bpf_prog_type_BPF_PROG_TYPE_PERF_EVENT,
1343            ProgramType::RawTracepoint => bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT,
1344            ProgramType::RawTracepointWritable => {
1345                bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
1346            }
1347            ProgramType::SchedAct => bpf_prog_type_BPF_PROG_TYPE_SCHED_ACT,
1348            ProgramType::SchedCls => bpf_prog_type_BPF_PROG_TYPE_SCHED_CLS,
1349            ProgramType::SkLookup => bpf_prog_type_BPF_PROG_TYPE_SK_LOOKUP,
1350            ProgramType::SkMsg => bpf_prog_type_BPF_PROG_TYPE_SK_MSG,
1351            ProgramType::SkReuseport => bpf_prog_type_BPF_PROG_TYPE_SK_REUSEPORT,
1352            ProgramType::SkSkb => bpf_prog_type_BPF_PROG_TYPE_SK_SKB,
1353            ProgramType::SockOps => bpf_prog_type_BPF_PROG_TYPE_SOCK_OPS,
1354            ProgramType::SocketFilter => bpf_prog_type_BPF_PROG_TYPE_SOCKET_FILTER,
1355            ProgramType::StructOps => bpf_prog_type_BPF_PROG_TYPE_STRUCT_OPS,
1356            ProgramType::Syscall => bpf_prog_type_BPF_PROG_TYPE_SYSCALL,
1357            ProgramType::Tracepoint => bpf_prog_type_BPF_PROG_TYPE_TRACEPOINT,
1358            ProgramType::Tracing => bpf_prog_type_BPF_PROG_TYPE_TRACING,
1359            ProgramType::Unspec => bpf_prog_type_BPF_PROG_TYPE_UNSPEC,
1360            ProgramType::Xdp => bpf_prog_type_BPF_PROG_TYPE_XDP,
1361            ProgramType::Fuse => BPF_PROG_TYPE_FUSE,
1362        }
1363    }
1364}
1365
1366impl ProgramType {
1367    pub fn get_helpers(self) -> HashMap<u32, &'static HelperDefinition> {
1368        BPF_HELPERS_DEFINITIONS
1369            .iter()
1370            .filter_map(|(filter, helper)| filter.accept(self).then_some((helper.index, helper)))
1371            .collect()
1372    }
1373
1374    pub fn get_args(
1375        self,
1376        expected_attach_type: AttachType,
1377    ) -> Result<&'static [Type], EbpfApiError> {
1378        let args = match self {
1379            Self::SocketFilter => &SOCKET_FILTER_ARGS,
1380            Self::SchedAct | Self::SchedCls => &SCHED_ARGS,
1381            Self::CgroupSkb => match expected_attach_type {
1382                AttachType::Unspecified
1383                | AttachType::CgroupInetIngress
1384                | AttachType::CgroupInetEgress => &CGROUP_SKB_ARGS,
1385                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1386            },
1387
1388            Self::Xdp => &XDP_MD_ARGS,
1389            Self::Kprobe => &BPF_USER_PT_REGS_T_ARGS,
1390            Self::Tracepoint => &BPF_TRACEPOINT_ARGS,
1391            Self::RawTracepoint => &BPF_RAW_TRACEPOINT_ARGS,
1392
1393            Self::CgroupSock => match expected_attach_type {
1394                AttachType::Unspecified
1395                | AttachType::CgroupInetIngress
1396                | AttachType::CgroupInetSockCreate
1397                | AttachType::CgroupInet4PostBind
1398                | AttachType::CgroupInet6PostBind
1399                | AttachType::CgroupInetSockRelease => &BPF_SOCK_ARGS,
1400                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1401            },
1402
1403            Self::CgroupSockopt => match expected_attach_type {
1404                AttachType::CgroupGetsockopt | AttachType::CgroupSetsockopt => &BPF_SOCKOPT_ARGS,
1405                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1406            },
1407
1408            Self::CgroupSockAddr => match expected_attach_type {
1409                AttachType::CgroupInet4Bind
1410                | AttachType::CgroupInet4Connect
1411                | AttachType::CgroupUdp4Sendmsg
1412                | AttachType::CgroupUdp4Recvmsg
1413                | AttachType::CgroupInet4Getpeername
1414                | AttachType::CgroupInet4Getsockname => &BPF_SOCK_ADDR_INET4_ARGS,
1415
1416                AttachType::CgroupInet6Bind
1417                | AttachType::CgroupInet6Connect
1418                | AttachType::CgroupUdp6Sendmsg
1419                | AttachType::CgroupUdp6Recvmsg
1420                | AttachType::CgroupInet6Getpeername
1421                | AttachType::CgroupInet6Getsockname => &BPF_SOCK_ADDR_INET6_ARGS,
1422
1423                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1424            },
1425
1426            Self::Fuse => &BPF_FUSE_ARGS,
1427
1428            Self::CgroupDevice
1429            | Self::CgroupSysctl
1430            | Self::Ext
1431            | Self::FlowDissector
1432            | Self::LircMode2
1433            | Self::Lsm
1434            | Self::LwtIn
1435            | Self::LwtOut
1436            | Self::LwtSeg6Local
1437            | Self::LwtXmit
1438            | Self::Netfilter
1439            | Self::PerfEvent
1440            | Self::RawTracepointWritable
1441            | Self::SkLookup
1442            | Self::SkMsg
1443            | Self::SkReuseport
1444            | Self::SkSkb
1445            | Self::SockOps
1446            | Self::StructOps
1447            | Self::Syscall
1448            | Self::Tracing
1449            | Self::Unspec => return Err(EbpfApiError::UnsupportedProgramType(self)),
1450        };
1451        Ok(args)
1452    }
1453
1454    pub fn create_calling_context(
1455        self,
1456        expected_attach_type: AttachType,
1457        maps: Vec<MapSchema>,
1458    ) -> Result<CallingContext, EbpfApiError> {
1459        let args = self.get_args(expected_attach_type)?.to_vec();
1460        let packet_type = match self {
1461            Self::SocketFilter => Some(SOCKET_FILTER_SK_BUF_TYPE.clone()),
1462            Self::SchedAct | Self::SchedCls => Some(SCHED_ARG_TYPE.clone()),
1463            _ => None,
1464        };
1465        Ok(CallingContext { maps, helpers: self.get_helpers(), args, packet_type })
1466    }
1467}
1468
1469#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1470pub enum AttachType {
1471    CgroupInetIngress,
1472    CgroupInetEgress,
1473    CgroupInetSockCreate,
1474    CgroupSockOps,
1475    SkSkbStreamParser,
1476    SkSkbStreamVerdict,
1477    CgroupDevice,
1478    SkMsgVerdict,
1479    CgroupInet4Bind,
1480    CgroupInet6Bind,
1481    CgroupInet4Connect,
1482    CgroupInet6Connect,
1483    CgroupInet4PostBind,
1484    CgroupInet6PostBind,
1485    CgroupUdp4Sendmsg,
1486    CgroupUdp6Sendmsg,
1487    LircMode2,
1488    FlowDissector,
1489    CgroupSysctl,
1490    CgroupUdp4Recvmsg,
1491    CgroupUdp6Recvmsg,
1492    CgroupGetsockopt,
1493    CgroupSetsockopt,
1494    TraceRawTp,
1495    TraceFentry,
1496    TraceFexit,
1497    ModifyReturn,
1498    LsmMac,
1499    TraceIter,
1500    CgroupInet4Getpeername,
1501    CgroupInet6Getpeername,
1502    CgroupInet4Getsockname,
1503    CgroupInet6Getsockname,
1504    XdpDevmap,
1505    CgroupInetSockRelease,
1506    XdpCpumap,
1507    SkLookup,
1508    Xdp,
1509    SkSkbVerdict,
1510    SkReuseportSelect,
1511    SkReuseportSelectOrMigrate,
1512    PerfEvent,
1513    TraceKprobeMulti,
1514    LsmCgroup,
1515    StructOps,
1516    Netfilter,
1517    TcxIngress,
1518    TcxEgress,
1519    TraceUprobeMulti,
1520    CgroupUnixConnect,
1521    CgroupUnixSendmsg,
1522    CgroupUnixRecvmsg,
1523    CgroupUnixGetpeername,
1524    CgroupUnixGetsockname,
1525    NetkitPrimary,
1526    NetkitPeer,
1527    TraceKprobeSession,
1528
1529    // Corresponds to `attach_type=-1`. Linux allows this value in
1530    // `expected_attach_type` for some `program_types`
1531    Unspecified,
1532
1533    // Corresponds to any `attach_type` value other than -1 and
1534    // `bpf_attach_type` enum values.
1535    Invalid(u32),
1536}
1537
1538impl From<u32> for AttachType {
1539    fn from(attach_type: u32) -> Self {
1540        match attach_type {
1541            #![allow(non_upper_case_globals)]
1542            bpf_attach_type_BPF_CGROUP_INET_INGRESS => Self::CgroupInetIngress,
1543            bpf_attach_type_BPF_CGROUP_INET_EGRESS => Self::CgroupInetEgress,
1544            bpf_attach_type_BPF_CGROUP_INET_SOCK_CREATE => Self::CgroupInetSockCreate,
1545            bpf_attach_type_BPF_CGROUP_SOCK_OPS => Self::CgroupSockOps,
1546            bpf_attach_type_BPF_SK_SKB_STREAM_PARSER => Self::SkSkbStreamParser,
1547            bpf_attach_type_BPF_SK_SKB_STREAM_VERDICT => Self::SkSkbStreamVerdict,
1548            bpf_attach_type_BPF_CGROUP_DEVICE => Self::CgroupDevice,
1549            bpf_attach_type_BPF_SK_MSG_VERDICT => Self::SkMsgVerdict,
1550            bpf_attach_type_BPF_CGROUP_INET4_BIND => Self::CgroupInet4Bind,
1551            bpf_attach_type_BPF_CGROUP_INET6_BIND => Self::CgroupInet6Bind,
1552            bpf_attach_type_BPF_CGROUP_INET4_CONNECT => Self::CgroupInet4Connect,
1553            bpf_attach_type_BPF_CGROUP_INET6_CONNECT => Self::CgroupInet6Connect,
1554            bpf_attach_type_BPF_CGROUP_INET4_POST_BIND => Self::CgroupInet4PostBind,
1555            bpf_attach_type_BPF_CGROUP_INET6_POST_BIND => Self::CgroupInet6PostBind,
1556            bpf_attach_type_BPF_CGROUP_UDP4_SENDMSG => Self::CgroupUdp4Sendmsg,
1557            bpf_attach_type_BPF_CGROUP_UDP6_SENDMSG => Self::CgroupUdp6Sendmsg,
1558            bpf_attach_type_BPF_LIRC_MODE2 => Self::LircMode2,
1559            bpf_attach_type_BPF_FLOW_DISSECTOR => Self::FlowDissector,
1560            bpf_attach_type_BPF_CGROUP_SYSCTL => Self::CgroupSysctl,
1561            bpf_attach_type_BPF_CGROUP_UDP4_RECVMSG => Self::CgroupUdp4Recvmsg,
1562            bpf_attach_type_BPF_CGROUP_UDP6_RECVMSG => Self::CgroupUdp6Recvmsg,
1563            bpf_attach_type_BPF_CGROUP_GETSOCKOPT => Self::CgroupGetsockopt,
1564            bpf_attach_type_BPF_CGROUP_SETSOCKOPT => Self::CgroupSetsockopt,
1565            bpf_attach_type_BPF_TRACE_RAW_TP => Self::TraceRawTp,
1566            bpf_attach_type_BPF_TRACE_FENTRY => Self::TraceFentry,
1567            bpf_attach_type_BPF_TRACE_FEXIT => Self::TraceFexit,
1568            bpf_attach_type_BPF_MODIFY_RETURN => Self::ModifyReturn,
1569            bpf_attach_type_BPF_LSM_MAC => Self::LsmMac,
1570            bpf_attach_type_BPF_TRACE_ITER => Self::TraceIter,
1571            bpf_attach_type_BPF_CGROUP_INET4_GETPEERNAME => Self::CgroupInet4Getpeername,
1572            bpf_attach_type_BPF_CGROUP_INET6_GETPEERNAME => Self::CgroupInet6Getpeername,
1573            bpf_attach_type_BPF_CGROUP_INET4_GETSOCKNAME => Self::CgroupInet4Getsockname,
1574            bpf_attach_type_BPF_CGROUP_INET6_GETSOCKNAME => Self::CgroupInet6Getsockname,
1575            bpf_attach_type_BPF_XDP_DEVMAP => Self::XdpDevmap,
1576            bpf_attach_type_BPF_CGROUP_INET_SOCK_RELEASE => Self::CgroupInetSockRelease,
1577            bpf_attach_type_BPF_XDP_CPUMAP => Self::XdpCpumap,
1578            bpf_attach_type_BPF_SK_LOOKUP => Self::SkLookup,
1579            bpf_attach_type_BPF_XDP => Self::Xdp,
1580            bpf_attach_type_BPF_SK_SKB_VERDICT => Self::SkSkbVerdict,
1581            bpf_attach_type_BPF_SK_REUSEPORT_SELECT => Self::SkReuseportSelect,
1582            bpf_attach_type_BPF_SK_REUSEPORT_SELECT_OR_MIGRATE => Self::SkReuseportSelectOrMigrate,
1583            bpf_attach_type_BPF_PERF_EVENT => Self::PerfEvent,
1584            bpf_attach_type_BPF_TRACE_KPROBE_MULTI => Self::TraceKprobeMulti,
1585            bpf_attach_type_BPF_LSM_CGROUP => Self::LsmCgroup,
1586            bpf_attach_type_BPF_STRUCT_OPS => Self::StructOps,
1587            bpf_attach_type_BPF_NETFILTER => Self::Netfilter,
1588            bpf_attach_type_BPF_TCX_INGRESS => Self::TcxIngress,
1589            bpf_attach_type_BPF_TCX_EGRESS => Self::TcxEgress,
1590            bpf_attach_type_BPF_TRACE_UPROBE_MULTI => Self::TraceUprobeMulti,
1591            bpf_attach_type_BPF_CGROUP_UNIX_CONNECT => Self::CgroupUnixConnect,
1592            bpf_attach_type_BPF_CGROUP_UNIX_SENDMSG => Self::CgroupUnixSendmsg,
1593            bpf_attach_type_BPF_CGROUP_UNIX_RECVMSG => Self::CgroupUnixRecvmsg,
1594            bpf_attach_type_BPF_CGROUP_UNIX_GETPEERNAME => Self::CgroupUnixGetpeername,
1595            bpf_attach_type_BPF_CGROUP_UNIX_GETSOCKNAME => Self::CgroupUnixGetsockname,
1596            bpf_attach_type_BPF_NETKIT_PRIMARY => Self::NetkitPrimary,
1597            bpf_attach_type_BPF_NETKIT_PEER => Self::NetkitPeer,
1598            bpf_attach_type_BPF_TRACE_KPROBE_SESSION => Self::TraceKprobeSession,
1599
1600            u32::MAX => Self::Unspecified,
1601            _ => Self::Invalid(attach_type),
1602        }
1603    }
1604}
1605
1606impl From<AttachType> for u32 {
1607    fn from(attach_type: AttachType) -> Self {
1608        match attach_type {
1609            AttachType::CgroupInetIngress => bpf_attach_type_BPF_CGROUP_INET_INGRESS,
1610            AttachType::CgroupInetEgress => bpf_attach_type_BPF_CGROUP_INET_EGRESS,
1611            AttachType::CgroupInetSockCreate => bpf_attach_type_BPF_CGROUP_INET_SOCK_CREATE,
1612            AttachType::CgroupSockOps => bpf_attach_type_BPF_CGROUP_SOCK_OPS,
1613            AttachType::SkSkbStreamParser => bpf_attach_type_BPF_SK_SKB_STREAM_PARSER,
1614            AttachType::SkSkbStreamVerdict => bpf_attach_type_BPF_SK_SKB_STREAM_VERDICT,
1615            AttachType::CgroupDevice => bpf_attach_type_BPF_CGROUP_DEVICE,
1616            AttachType::SkMsgVerdict => bpf_attach_type_BPF_SK_MSG_VERDICT,
1617            AttachType::CgroupInet4Bind => bpf_attach_type_BPF_CGROUP_INET4_BIND,
1618            AttachType::CgroupInet6Bind => bpf_attach_type_BPF_CGROUP_INET6_BIND,
1619            AttachType::CgroupInet4Connect => bpf_attach_type_BPF_CGROUP_INET4_CONNECT,
1620            AttachType::CgroupInet6Connect => bpf_attach_type_BPF_CGROUP_INET6_CONNECT,
1621            AttachType::CgroupInet4PostBind => bpf_attach_type_BPF_CGROUP_INET4_POST_BIND,
1622            AttachType::CgroupInet6PostBind => bpf_attach_type_BPF_CGROUP_INET6_POST_BIND,
1623            AttachType::CgroupUdp4Sendmsg => bpf_attach_type_BPF_CGROUP_UDP4_SENDMSG,
1624            AttachType::CgroupUdp6Sendmsg => bpf_attach_type_BPF_CGROUP_UDP6_SENDMSG,
1625            AttachType::LircMode2 => bpf_attach_type_BPF_LIRC_MODE2,
1626            AttachType::FlowDissector => bpf_attach_type_BPF_FLOW_DISSECTOR,
1627            AttachType::CgroupSysctl => bpf_attach_type_BPF_CGROUP_SYSCTL,
1628            AttachType::CgroupUdp4Recvmsg => bpf_attach_type_BPF_CGROUP_UDP4_RECVMSG,
1629            AttachType::CgroupUdp6Recvmsg => bpf_attach_type_BPF_CGROUP_UDP6_RECVMSG,
1630            AttachType::CgroupGetsockopt => bpf_attach_type_BPF_CGROUP_GETSOCKOPT,
1631            AttachType::CgroupSetsockopt => bpf_attach_type_BPF_CGROUP_SETSOCKOPT,
1632            AttachType::TraceRawTp => bpf_attach_type_BPF_TRACE_RAW_TP,
1633            AttachType::TraceFentry => bpf_attach_type_BPF_TRACE_FENTRY,
1634            AttachType::TraceFexit => bpf_attach_type_BPF_TRACE_FEXIT,
1635            AttachType::ModifyReturn => bpf_attach_type_BPF_MODIFY_RETURN,
1636            AttachType::LsmMac => bpf_attach_type_BPF_LSM_MAC,
1637            AttachType::TraceIter => bpf_attach_type_BPF_TRACE_ITER,
1638            AttachType::CgroupInet4Getpeername => bpf_attach_type_BPF_CGROUP_INET4_GETPEERNAME,
1639            AttachType::CgroupInet6Getpeername => bpf_attach_type_BPF_CGROUP_INET6_GETPEERNAME,
1640            AttachType::CgroupInet4Getsockname => bpf_attach_type_BPF_CGROUP_INET4_GETSOCKNAME,
1641            AttachType::CgroupInet6Getsockname => bpf_attach_type_BPF_CGROUP_INET6_GETSOCKNAME,
1642            AttachType::XdpDevmap => bpf_attach_type_BPF_XDP_DEVMAP,
1643            AttachType::CgroupInetSockRelease => bpf_attach_type_BPF_CGROUP_INET_SOCK_RELEASE,
1644            AttachType::XdpCpumap => bpf_attach_type_BPF_XDP_CPUMAP,
1645            AttachType::SkLookup => bpf_attach_type_BPF_SK_LOOKUP,
1646            AttachType::Xdp => bpf_attach_type_BPF_XDP,
1647            AttachType::SkSkbVerdict => bpf_attach_type_BPF_SK_SKB_VERDICT,
1648            AttachType::SkReuseportSelect => bpf_attach_type_BPF_SK_REUSEPORT_SELECT,
1649            AttachType::SkReuseportSelectOrMigrate => {
1650                bpf_attach_type_BPF_SK_REUSEPORT_SELECT_OR_MIGRATE
1651            }
1652            AttachType::PerfEvent => bpf_attach_type_BPF_PERF_EVENT,
1653            AttachType::TraceKprobeMulti => bpf_attach_type_BPF_TRACE_KPROBE_MULTI,
1654            AttachType::LsmCgroup => bpf_attach_type_BPF_LSM_CGROUP,
1655            AttachType::StructOps => bpf_attach_type_BPF_STRUCT_OPS,
1656            AttachType::Netfilter => bpf_attach_type_BPF_NETFILTER,
1657            AttachType::TcxIngress => bpf_attach_type_BPF_TCX_INGRESS,
1658            AttachType::TcxEgress => bpf_attach_type_BPF_TCX_EGRESS,
1659            AttachType::TraceUprobeMulti => bpf_attach_type_BPF_TRACE_UPROBE_MULTI,
1660            AttachType::CgroupUnixConnect => bpf_attach_type_BPF_CGROUP_UNIX_CONNECT,
1661            AttachType::CgroupUnixSendmsg => bpf_attach_type_BPF_CGROUP_UNIX_SENDMSG,
1662            AttachType::CgroupUnixRecvmsg => bpf_attach_type_BPF_CGROUP_UNIX_RECVMSG,
1663            AttachType::CgroupUnixGetpeername => bpf_attach_type_BPF_CGROUP_UNIX_GETPEERNAME,
1664            AttachType::CgroupUnixGetsockname => bpf_attach_type_BPF_CGROUP_UNIX_GETSOCKNAME,
1665            AttachType::NetkitPrimary => bpf_attach_type_BPF_NETKIT_PRIMARY,
1666            AttachType::NetkitPeer => bpf_attach_type_BPF_NETKIT_PEER,
1667            AttachType::TraceKprobeSession => bpf_attach_type_BPF_TRACE_KPROBE_SESSION,
1668            AttachType::Unspecified => u32::MAX,
1669            AttachType::Invalid(attach_type) => attach_type,
1670        }
1671    }
1672}
1673
1674impl From<AttachType> for u64 {
1675    fn from(attach_type: AttachType) -> Self {
1676        (u32::from(attach_type)).into()
1677    }
1678}
1679
1680impl AttachType {
1681    pub fn is_cgroup(&self) -> bool {
1682        match self {
1683            Self::CgroupInetIngress
1684            | Self::CgroupInetEgress
1685            | Self::CgroupInetSockCreate
1686            | Self::CgroupSockOps
1687            | Self::CgroupDevice
1688            | Self::CgroupInet4Bind
1689            | Self::CgroupInet6Bind
1690            | Self::CgroupInet4Connect
1691            | Self::CgroupInet6Connect
1692            | Self::CgroupInet4PostBind
1693            | Self::CgroupInet6PostBind
1694            | Self::CgroupUdp4Sendmsg
1695            | Self::CgroupUdp6Sendmsg
1696            | Self::CgroupSysctl
1697            | Self::CgroupUdp4Recvmsg
1698            | Self::CgroupUdp6Recvmsg
1699            | Self::CgroupGetsockopt
1700            | Self::CgroupSetsockopt
1701            | Self::CgroupInet4Getpeername
1702            | Self::CgroupInet6Getpeername
1703            | Self::CgroupInet4Getsockname
1704            | Self::CgroupInet6Getsockname
1705            | Self::CgroupInetSockRelease
1706            | Self::CgroupUnixConnect
1707            | Self::CgroupUnixSendmsg
1708            | Self::CgroupUnixRecvmsg
1709            | Self::CgroupUnixGetpeername
1710            | Self::CgroupUnixGetsockname => true,
1711            _ => false,
1712        }
1713    }
1714
1715    pub fn get_program_type(&self) -> ProgramType {
1716        match self {
1717            Self::CgroupInetIngress | Self::CgroupInetEgress => ProgramType::CgroupSkb,
1718            Self::CgroupInetSockCreate
1719            | Self::CgroupInet4PostBind
1720            | Self::CgroupInet6PostBind
1721            | Self::CgroupInetSockRelease => ProgramType::CgroupSock,
1722            Self::CgroupSockOps | Self::CgroupGetsockopt | Self::CgroupSetsockopt => {
1723                ProgramType::CgroupSockopt
1724            }
1725            Self::CgroupDevice => ProgramType::CgroupDevice,
1726            Self::CgroupInet4Bind
1727            | Self::CgroupInet6Bind
1728            | Self::CgroupInet4Connect
1729            | Self::CgroupInet6Connect
1730            | Self::CgroupUdp4Sendmsg
1731            | Self::CgroupUdp6Sendmsg
1732            | Self::CgroupUdp4Recvmsg
1733            | Self::CgroupUdp6Recvmsg
1734            | Self::CgroupInet4Getpeername
1735            | Self::CgroupInet6Getpeername
1736            | Self::CgroupInet4Getsockname
1737            | Self::CgroupInet6Getsockname
1738            | Self::CgroupUnixConnect
1739            | Self::CgroupUnixSendmsg
1740            | Self::CgroupUnixRecvmsg
1741            | Self::CgroupUnixGetpeername
1742            | Self::CgroupUnixGetsockname => ProgramType::CgroupSockAddr,
1743            Self::CgroupSysctl => ProgramType::CgroupSysctl,
1744            Self::FlowDissector => ProgramType::FlowDissector,
1745            Self::LircMode2 => ProgramType::LircMode2,
1746            Self::LsmMac | Self::LsmCgroup => ProgramType::Lsm,
1747            Self::Netfilter => ProgramType::Netfilter,
1748            Self::PerfEvent => ProgramType::PerfEvent,
1749            Self::SkLookup => ProgramType::SkLookup,
1750            Self::SkMsgVerdict | Self::SkSkbVerdict => ProgramType::SkMsg,
1751            Self::SkReuseportSelect | Self::SkReuseportSelectOrMigrate => ProgramType::SkReuseport,
1752            Self::SkSkbStreamParser | Self::SkSkbStreamVerdict => ProgramType::SkSkb,
1753            Self::StructOps => ProgramType::StructOps,
1754            Self::TcxIngress | Self::TcxEgress | Self::NetkitPrimary | Self::NetkitPeer => {
1755                ProgramType::SchedCls
1756            }
1757            Self::TraceKprobeMulti | Self::TraceUprobeMulti | Self::TraceKprobeSession => {
1758                ProgramType::Kprobe
1759            }
1760            Self::TraceRawTp
1761            | Self::TraceFentry
1762            | Self::TraceFexit
1763            | Self::ModifyReturn
1764            | Self::TraceIter => ProgramType::Tracing,
1765            Self::XdpDevmap | Self::XdpCpumap | Self::Xdp => ProgramType::Xdp,
1766            Self::Unspecified | Self::Invalid(_) => ProgramType::Unspec,
1767        }
1768    }
1769
1770    // Returns true if the attachment should allow programs created with the
1771    // specified `expected_attach_type`.
1772    pub fn is_compatible_with_expected_attach_type(self, expected: AttachType) -> bool {
1773        // See https://docs.ebpf.io/linux/syscall/BPF_PROG_LOAD/#expected_attach_type.
1774        match self {
1775            // Egress and Ingress attachments are interchangeable. Also `expected_attach_type=-1` is
1776            // allowed in both cases.
1777            Self::CgroupInetIngress | Self::CgroupInetEgress => matches!(
1778                expected,
1779                Self::Unspecified | Self::CgroupInetIngress | Self::CgroupInetEgress
1780            ),
1781
1782            // These attachments allow `expected_attach_type` to be set to
1783            // -1 or 0 (BPF_CGROUP_INET_INGRESS).
1784            Self::CgroupInetSockCreate | Self::CgroupSockOps => {
1785                self == expected || matches!(expected, Self::Unspecified | Self::CgroupInetIngress)
1786            }
1787
1788            // For these attachments `expected_attach_type` must match.
1789            Self::CgroupGetsockopt
1790            | Self::CgroupInet4Bind
1791            | Self::CgroupInet4Connect
1792            | Self::CgroupInet4Getpeername
1793            | Self::CgroupInet4Getsockname
1794            | Self::CgroupInet4PostBind
1795            | Self::CgroupInet6Bind
1796            | Self::CgroupInet6Connect
1797            | Self::CgroupInet6Getpeername
1798            | Self::CgroupInet6Getsockname
1799            | Self::CgroupInet6PostBind
1800            | Self::CgroupInetSockRelease
1801            | Self::CgroupSetsockopt
1802            | Self::CgroupUdp4Recvmsg
1803            | Self::CgroupUdp4Sendmsg
1804            | Self::CgroupUdp6Recvmsg
1805            | Self::CgroupUdp6Sendmsg
1806            | Self::CgroupUnixConnect
1807            | Self::CgroupUnixGetpeername
1808            | Self::CgroupUnixGetsockname
1809            | Self::CgroupUnixRecvmsg
1810            | Self::CgroupUnixSendmsg => self == expected,
1811
1812            // `expected_attach_type` is ignored for all other attachments.
1813            _ => true,
1814        }
1815    }
1816}
1817
1818// Offset used to access auxiliary packet information in cBPF.
1819pub const SKF_AD_OFF: i32 = linux_uapi::SKF_AD_OFF;
1820pub const SKF_AD_PROTOCOL: i32 = linux_uapi::SKF_AD_PROTOCOL as i32;
1821pub const SKF_AD_PKTTYPE: i32 = linux_uapi::SKF_AD_PKTTYPE as i32;
1822pub const SKF_AD_IFINDEX: i32 = linux_uapi::SKF_AD_IFINDEX as i32;
1823pub const SKF_AD_NLATTR: i32 = linux_uapi::SKF_AD_NLATTR as i32;
1824pub const SKF_AD_NLATTR_NEST: i32 = linux_uapi::SKF_AD_NLATTR_NEST as i32;
1825pub const SKF_AD_MARK: i32 = linux_uapi::SKF_AD_MARK as i32;
1826pub const SKF_AD_QUEUE: i32 = linux_uapi::SKF_AD_QUEUE as i32;
1827pub const SKF_AD_HATYPE: i32 = linux_uapi::SKF_AD_HATYPE as i32;
1828pub const SKF_AD_RXHASH: i32 = linux_uapi::SKF_AD_RXHASH as i32;
1829pub const SKF_AD_CPU: i32 = linux_uapi::SKF_AD_CPU as i32;
1830pub const SKF_AD_ALU_XOR_X: i32 = linux_uapi::SKF_AD_ALU_XOR_X as i32;
1831pub const SKF_AD_VLAN_TAG: i32 = linux_uapi::SKF_AD_VLAN_TAG as i32;
1832pub const SKF_AD_VLAN_TAG_PRESENT: i32 = linux_uapi::SKF_AD_VLAN_TAG_PRESENT as i32;
1833pub const SKF_AD_PAY_OFFSET: i32 = linux_uapi::SKF_AD_PAY_OFFSET as i32;
1834pub const SKF_AD_RANDOM: i32 = linux_uapi::SKF_AD_RANDOM as i32;
1835pub const SKF_AD_VLAN_TPID: i32 = linux_uapi::SKF_AD_VLAN_TPID as i32;
1836pub const SKF_AD_MAX: i32 = linux_uapi::SKF_AD_MAX as i32;
1837
1838// Offset used to reference IP headers in cBPF.
1839pub const SKF_NET_OFF: i32 = linux_uapi::SKF_NET_OFF;
1840
1841// Offset used to reference Ethernet headers in cBPF.
1842pub const SKF_LL_OFF: i32 = linux_uapi::SKF_LL_OFF;
1843
1844pub const SECCOMP_CBPF_CONFIG: CbpfConfig = CbpfConfig {
1845    len: CbpfLenInstruction::Static { len: size_of::<seccomp_data>() as i32 },
1846    allow_msh: false,
1847};
1848
1849pub const SOCKET_FILTER_CBPF_CONFIG: CbpfConfig = CbpfConfig {
1850    len: CbpfLenInstruction::ContextField { offset: offset_of!(__sk_buff, len) as i16 },
1851    allow_msh: true,
1852};