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, PointerOrigin,
8    StructDescriptor, 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    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
84#[derive(Clone, Default, Debug)]
85pub struct BpfTypeFilter(Vec<ProgramType>);
86
87impl<T: IntoIterator<Item = ProgramType>> From<T> for BpfTypeFilter {
88    fn from(types: T) -> Self {
89        Self(types.into_iter().collect())
90    }
91}
92
93impl BpfTypeFilter {
94    pub fn accept(&self, program_type: ProgramType) -> bool {
95        self.0.is_empty() || self.0.iter().find(|v| **v == program_type).is_some()
96    }
97}
98
99// Map types that should not be allowed in `map_lookup_elem`, `map_update_elem`
100// and `map_delete_elem`.
101static SPECIAL_MAP_TYPES: &[linux_uapi::bpf_map_type] =
102    &[bpf_map_type_BPF_MAP_TYPE_SK_STORAGE, bpf_map_type_BPF_MAP_TYPE_RINGBUF];
103
104static BPF_HELPERS_DEFINITIONS: LazyLock<Vec<(BpfTypeFilter, HelperDefinition)>> =
105    LazyLock::new(|| {
106        vec![
107            (
108                BpfTypeFilter::default(),
109                HelperDefinition {
110                    index: bpf_func_id_BPF_FUNC_map_lookup_elem,
111                    name: "map_lookup_elem",
112                    signature: FunctionSignature {
113                        args: vec![
114                            Type::ConstPtrToMapParameter {
115                                filter: MapTypeFilter::DenyList(SPECIAL_MAP_TYPES),
116                                must_be_writable: false,
117                            },
118                            Type::MapKeyParameter { map_ptr_index: 0 },
119                        ],
120                        return_value: Type::NullOrParameter(Box::new(Type::MapValueParameter {
121                            map_ptr_index: 0,
122                        })),
123                        invalidate_array_bounds: false,
124                    },
125                },
126            ),
127            (
128                BpfTypeFilter::default(),
129                HelperDefinition {
130                    index: bpf_func_id_BPF_FUNC_map_update_elem,
131                    name: "map_update_elem",
132                    signature: FunctionSignature {
133                        args: vec![
134                            Type::ConstPtrToMapParameter {
135                                filter: MapTypeFilter::DenyList(SPECIAL_MAP_TYPES),
136                                must_be_writable: true,
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                                must_be_writable: true,
157                            },
158                            Type::MapKeyParameter { map_ptr_index: 0 },
159                        ],
160                        return_value: Type::UNKNOWN_SCALAR,
161                        invalidate_array_bounds: false,
162                    },
163                },
164            ),
165            (
166                BpfTypeFilter::default(),
167                HelperDefinition {
168                    index: bpf_func_id_BPF_FUNC_trace_printk,
169                    name: "trace_printk",
170                    signature: FunctionSignature {
171                        // TODO("https://fxbug.dev/287120494"): Specify arguments
172                        args: vec![],
173                        return_value: Type::UNKNOWN_SCALAR,
174                        invalidate_array_bounds: false,
175                    },
176                },
177            ),
178            (
179                BpfTypeFilter::default(),
180                HelperDefinition {
181                    index: bpf_func_id_BPF_FUNC_ktime_get_ns,
182                    name: "ktime_get_ns",
183                    signature: FunctionSignature {
184                        args: vec![],
185                        return_value: Type::UNKNOWN_SCALAR,
186                        invalidate_array_bounds: false,
187                    },
188                },
189            ),
190            (
191                BpfTypeFilter::default(),
192                HelperDefinition {
193                    index: bpf_func_id_BPF_FUNC_probe_read_user,
194                    name: "probe_read_user",
195                    signature: FunctionSignature {
196                        args: vec![
197                            Type::MemoryParameter {
198                                size: MemoryParameterSize::Reference { index: 1 },
199                                input: false,
200                                output: true,
201                            },
202                            Type::ScalarValueParameter,
203                            Type::AnyParameter,
204                        ],
205                        return_value: Type::UNKNOWN_SCALAR,
206                        invalidate_array_bounds: false,
207                    },
208                },
209            ),
210            (
211                BpfTypeFilter::default(),
212                HelperDefinition {
213                    index: bpf_func_id_BPF_FUNC_probe_read_user_str,
214                    name: "probe_read_user_str",
215                    signature: FunctionSignature {
216                        args: vec![
217                            Type::MemoryParameter {
218                                size: MemoryParameterSize::Reference { index: 1 },
219                                input: false,
220                                output: true,
221                            },
222                            Type::ScalarValueParameter,
223                            Type::ScalarValueParameter,
224                        ],
225                        return_value: Type::UNKNOWN_SCALAR,
226                        invalidate_array_bounds: false,
227                    },
228                },
229            ),
230            (
231                vec![
232                    ProgramType::CgroupSkb,
233                    ProgramType::SchedAct,
234                    ProgramType::SchedCls,
235                    ProgramType::SocketFilter,
236                ]
237                .into(),
238                HelperDefinition {
239                    index: bpf_func_id_BPF_FUNC_get_socket_uid,
240                    name: "get_socket_uid",
241                    signature: FunctionSignature {
242                        args: vec![Type::StructParameter { id: SK_BUF_ID.clone() }],
243                        return_value: Type::UNKNOWN_SCALAR,
244                        invalidate_array_bounds: false,
245                    },
246                },
247            ),
248            (
249                vec![
250                    ProgramType::CgroupSock,
251                    ProgramType::CgroupSockAddr,
252                    ProgramType::CgroupSockopt,
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::Kprobe,
273                    ProgramType::Tracepoint,
274                ]
275                .into(),
276                HelperDefinition {
277                    index: bpf_func_id_BPF_FUNC_get_current_pid_tgid,
278                    name: "get_current_pid_tgid",
279                    signature: FunctionSignature {
280                        args: vec![],
281                        return_value: Type::UNKNOWN_SCALAR,
282                        invalidate_array_bounds: false,
283                    },
284                },
285            ),
286            (
287                vec![ProgramType::SchedAct, ProgramType::SchedCls].into(),
288                HelperDefinition {
289                    index: bpf_func_id_BPF_FUNC_skb_pull_data,
290                    name: "skb_pull_data",
291                    signature: FunctionSignature {
292                        args: vec![
293                            Type::StructParameter { id: SK_BUF_ID.clone() },
294                            Type::ScalarValueParameter,
295                        ],
296                        return_value: Type::UNKNOWN_SCALAR,
297                        invalidate_array_bounds: true,
298                    },
299                },
300            ),
301            (
302                BpfTypeFilter::default(),
303                HelperDefinition {
304                    index: bpf_func_id_BPF_FUNC_ringbuf_reserve,
305                    name: "ringbuf_reserve",
306                    signature: FunctionSignature {
307                        args: vec![
308                            Type::ConstPtrToMapParameter {
309                                filter: MapTypeFilter::AllowList(&[
310                                    bpf_map_type_BPF_MAP_TYPE_RINGBUF,
311                                ]),
312                                must_be_writable: true,
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                                must_be_writable: false,
623                            },
624                            Type::StructParameter { id: BPF_SOCK_ID.clone() },
625                            Type::NullOrParameter(Box::new(Type::MapValueParameter {
626                                map_ptr_index: 0,
627                            })),
628                            Type::ScalarValueParameter,
629                        ],
630                        return_value: Type::NullOrParameter(Box::new(Type::MapValueParameter {
631                            map_ptr_index: 0,
632                        })),
633                        invalidate_array_bounds: false,
634                    },
635                },
636            ),
637            (
638                BpfTypeFilter::default(),
639                HelperDefinition {
640                    index: bpf_func_id_BPF_FUNC_get_smp_processor_id,
641                    name: "get_smp_processor_id",
642                    signature: FunctionSignature {
643                        args: vec![],
644                        return_value: Type::UNKNOWN_SCALAR,
645                        invalidate_array_bounds: false,
646                    },
647                },
648            ),
649            (
650                vec![ProgramType::CgroupSkb, ProgramType::SchedAct, ProgramType::SchedCls].into(),
651                HelperDefinition {
652                    index: bpf_func_id_BPF_FUNC_sk_fullsock,
653                    name: "sk_fullsock",
654                    signature: FunctionSignature {
655                        args: vec![Type::StructParameter { id: BPF_SOCK_ID.clone() }],
656                        return_value: Type::NullOrParameter(Box::new(ptr_to_mem_type::<bpf_sock>(
657                            BPF_SOCK_ID.clone(),
658                        ))),
659                        invalidate_array_bounds: false,
660                    },
661                },
662            ),
663            (
664                vec![
665                    ProgramType::CgroupDevice,
666                    ProgramType::CgroupSockopt,
667                    ProgramType::CgroupSysctl,
668                ]
669                .into(),
670                HelperDefinition {
671                    index: bpf_func_id_BPF_FUNC_set_retval,
672                    name: "set_retval",
673                    signature: FunctionSignature {
674                        args: vec![Type::ScalarValueParameter],
675                        return_value: Type::UNKNOWN_SCALAR,
676                        invalidate_array_bounds: false,
677                    },
678                },
679            ),
680            (
681                vec![
682                    ProgramType::CgroupDevice,
683                    ProgramType::CgroupSockopt,
684                    ProgramType::CgroupSysctl,
685                ]
686                .into(),
687                HelperDefinition {
688                    index: bpf_func_id_BPF_FUNC_get_retval,
689                    name: "get_retval",
690                    signature: FunctionSignature {
691                        args: vec![],
692                        return_value: Type::UNKNOWN_SCALAR,
693                        invalidate_array_bounds: false,
694                    },
695                },
696            ),
697            (
698                // Note that bpf_sk_lookup_tcp should also be available to CgroupAddr and Xdp
699                // programs, but those use different type for the first context parameter.
700                vec![
701                    ProgramType::CgroupSkb,
702                    ProgramType::SchedAct,
703                    ProgramType::SchedCls,
704                    ProgramType::SkSkb,
705                ]
706                .into(),
707                HelperDefinition {
708                    index: bpf_func_id_BPF_FUNC_sk_lookup_tcp,
709                    name: "sk_lookup_tcp",
710                    signature: FunctionSignature {
711                        args: vec![
712                            Type::StructParameter { id: SK_BUF_ID.clone() },
713                            Type::MemoryParameter {
714                                size: MemoryParameterSize::Reference { index: 2 },
715                                input: true,
716                                output: false,
717                            },
718                            Type::ScalarValueParameter,
719                            Type::ScalarValueParameter,
720                            Type::ScalarValueParameter,
721                        ],
722                        return_value: Type::NullOrParameter(Box::new(Type::ReleasableParameter {
723                            id: RELEASABLE_BPF_SOCK_PTR.clone(),
724                            inner: Box::new(BPF_SOCK_TYPE.clone()),
725                        })),
726                        invalidate_array_bounds: false,
727                    },
728                },
729            ),
730            (
731                // Note that bpf_sk_lookup_udp should also be available to CgroupAddr and Xdp
732                // programs, but those use different type for the first context parameter.
733                vec![
734                    ProgramType::CgroupSkb,
735                    ProgramType::SchedAct,
736                    ProgramType::SchedCls,
737                    ProgramType::SkSkb,
738                ]
739                .into(),
740                HelperDefinition {
741                    index: bpf_func_id_BPF_FUNC_sk_lookup_udp,
742                    name: "sk_lookup_udp",
743                    signature: FunctionSignature {
744                        args: vec![
745                            Type::StructParameter { id: SK_BUF_ID.clone() },
746                            Type::MemoryParameter {
747                                size: MemoryParameterSize::Reference { index: 2 },
748                                input: true,
749                                output: false,
750                            },
751                            Type::ScalarValueParameter,
752                            Type::ScalarValueParameter,
753                            Type::ScalarValueParameter,
754                        ],
755                        return_value: Type::NullOrParameter(Box::new(Type::ReleasableParameter {
756                            id: RELEASABLE_BPF_SOCK_PTR.clone(),
757                            inner: Box::new(BPF_SOCK_TYPE.clone()),
758                        })),
759                        invalidate_array_bounds: false,
760                    },
761                },
762            ),
763            (
764                vec![
765                    ProgramType::CgroupSkb,
766                    ProgramType::CgroupSockAddr,
767                    ProgramType::SchedAct,
768                    ProgramType::SchedCls,
769                    ProgramType::SkSkb,
770                    ProgramType::Xdp,
771                ]
772                .into(),
773                HelperDefinition {
774                    index: bpf_func_id_BPF_FUNC_sk_release,
775                    name: "sk_release",
776                    signature: FunctionSignature {
777                        args: vec![Type::ReleaseParameter { id: RELEASABLE_BPF_SOCK_PTR.clone() }],
778                        return_value: Type::UNKNOWN_SCALAR,
779                        invalidate_array_bounds: false,
780                    },
781                },
782            ),
783            (
784                vec![
785                    ProgramType::CgroupSkb,
786                    ProgramType::CgroupSock,
787                    ProgramType::CgroupSockopt,
788                    ProgramType::CgroupSockAddr,
789                    ProgramType::SchedAct,
790                    ProgramType::SchedCls,
791                    ProgramType::SkMsg,
792                    ProgramType::SocketFilter,
793                    ProgramType::SockOps,
794                ]
795                .into(),
796                HelperDefinition {
797                    index: bpf_func_id_BPF_FUNC_get_netns_cookie,
798                    name: "bpf_get_netns_cookie",
799                    signature: FunctionSignature {
800                        args: vec![Type::NullOrParameter(Box::new(Type::ContextParameter {
801                            parameter_index: 0,
802                        }))],
803                        return_value: Type::UNKNOWN_SCALAR,
804                        invalidate_array_bounds: false,
805                    },
806                },
807            ),
808        ]
809    });
810
811/// A type of a struct that may be passed to eBPF programs.
812#[derive(Copy, Clone, Debug, PartialEq, Eq)]
813pub enum StructId {
814    SkBuff = 1,
815    XdpMd = 2,
816    BpfUserPtRegs = 3,
817    BpfSock = 4,
818    BpfSockOpt = 5,
819    BpfSockAddr = 6,
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        }
838    }
839}
840
841impl TryFrom<&MemoryId> for StructId {
842    type Error = ();
843
844    fn try_from(value: &MemoryId) -> Result<Self, Self::Error> {
845        if *value == StructId::SkBuff.as_memory_id() {
846            Ok(StructId::SkBuff)
847        } else if *value == StructId::XdpMd.as_memory_id() {
848            Ok(StructId::XdpMd)
849        } else if *value == StructId::BpfUserPtRegs.as_memory_id() {
850            Ok(StructId::BpfUserPtRegs)
851        } else if *value == StructId::BpfSock.as_memory_id() {
852            Ok(StructId::BpfSock)
853        } else if *value == StructId::BpfSockOpt.as_memory_id() {
854            Ok(StructId::BpfSockOpt)
855        } else if *value == StructId::BpfSockAddr.as_memory_id() {
856            Ok(StructId::BpfSockAddr)
857        } else {
858            Err(())
859        }
860    }
861}
862
863impl From<febpf::StructId> for StructId {
864    fn from(value: febpf::StructId) -> Self {
865        match value {
866            febpf::StructId::SkBuff => StructId::SkBuff,
867            febpf::StructId::XdpMd => StructId::XdpMd,
868            febpf::StructId::BpfUserPtRegs => StructId::BpfUserPtRegs,
869            febpf::StructId::BpfSock => StructId::BpfSock,
870            febpf::StructId::BpfSockOpt => StructId::BpfSockOpt,
871            febpf::StructId::BpfSockAddr => StructId::BpfSockAddr,
872            febpf::StructId::__SourceBreaking { unknown_ordinal } => {
873                panic!("Invalid struct id: {}", unknown_ordinal)
874            }
875        }
876    }
877}
878
879fn scalar_field(offset: usize, size: usize) -> FieldDescriptor {
880    FieldDescriptor { offset, field_type: FieldType::Scalar { size } }
881}
882
883fn scalar_range(offset: usize, end_offset: usize) -> FieldDescriptor {
884    FieldDescriptor { offset, field_type: FieldType::Scalar { size: end_offset - offset } }
885}
886
887fn scalar_mut_range(offset: usize, end_offset: usize) -> FieldDescriptor {
888    FieldDescriptor { offset, field_type: FieldType::MutableScalar { size: end_offset - offset } }
889}
890
891fn scalar_u32_field(offset: usize) -> FieldDescriptor {
892    FieldDescriptor { offset, field_type: FieldType::Scalar { size: std::mem::size_of::<u32>() } }
893}
894
895fn scalar_u32_mut_field(offset: usize) -> FieldDescriptor {
896    FieldDescriptor {
897        offset,
898        field_type: FieldType::MutableScalar { size: std::mem::size_of::<u32>() },
899    }
900}
901
902fn scalar_u64_field(offset: usize) -> FieldDescriptor {
903    FieldDescriptor { offset, field_type: FieldType::Scalar { size: std::mem::size_of::<u64>() } }
904}
905
906fn array_start_field(offset: usize, id: MemoryId) -> FieldDescriptor {
907    FieldDescriptor { offset, field_type: FieldType::PtrToArray { id, is_32_bit: false } }
908}
909
910fn array_end_field(offset: usize, id: MemoryId) -> FieldDescriptor {
911    FieldDescriptor { offset, field_type: FieldType::PtrToEndArray { id, is_32_bit: false } }
912}
913
914fn array_start_32_field(offset: usize, id: MemoryId) -> FieldDescriptor {
915    FieldDescriptor { offset, field_type: FieldType::PtrToArray { id, is_32_bit: true } }
916}
917
918fn array_end_32_field(offset: usize, id: MemoryId) -> FieldDescriptor {
919    FieldDescriptor { offset, field_type: FieldType::PtrToEndArray { id, is_32_bit: true } }
920}
921
922fn ptr_to_mem_field<T: IntoBytes>(offset: usize, id: MemoryId) -> FieldDescriptor {
923    FieldDescriptor {
924        offset,
925        field_type: FieldType::PtrToMemory {
926            id,
927            buffer_size: std::mem::size_of::<T>(),
928            is_32_bit: false,
929        },
930    }
931}
932
933fn nullable_ptr_to_mem_field<T: IntoBytes>(offset: usize, id: MemoryId) -> FieldDescriptor {
934    FieldDescriptor {
935        offset,
936        field_type: FieldType::NullablePtrToMemory {
937            is_32_bit: false,
938            id,
939            buffer_size: std::mem::size_of::<T>(),
940        },
941    }
942}
943
944fn ptr_to_struct_type(id: MemoryId, fields: Vec<FieldDescriptor>) -> Type {
945    Type::PtrToStruct { id, offset: 0.into(), descriptor: Arc::new(StructDescriptor { fields }) }
946}
947
948fn ptr_to_mem_type<T: IntoBytes>(id: MemoryId) -> Type {
949    Type::PtrToMemory {
950        id,
951        offset: 0.into(),
952        buffer_size: std::mem::size_of::<T>() as u64,
953        origin: PointerOrigin::KernelReadOnly,
954    }
955}
956
957static RING_BUFFER_RESERVATION: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
958
959// Id for the value returned from `bpf_sk_lookup_xxx` helpers. It has to be
960// released by calling `bpf_sk_release`.
961static RELEASABLE_BPF_SOCK_PTR: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
962
963pub static SK_BUF_ID: MemoryId = StructId::SkBuff.as_memory_id();
964
965/// Type for the `__sk_buff` passed to `BPF_PROG_TYPE_SOCKET_FILTER` programs.
966pub static SOCKET_FILTER_SK_BUF_TYPE: LazyLock<Type> = LazyLock::new(|| {
967    ptr_to_struct_type(
968        SK_BUF_ID.clone(),
969        vec![
970            // All fields from the start of `__sk_buff` to `cb` are read-only scalars.
971            scalar_range(0, offset_of!(__sk_buff, cb)),
972            // `cb` is a mutable array.
973            scalar_mut_range(offset_of!(__sk_buff, cb), offset_of!(__sk_buff, hash)),
974            scalar_u32_field(offset_of!(__sk_buff, hash)),
975            scalar_u32_field(offset_of!(__sk_buff, napi_id)),
976            scalar_u32_field(offset_of!(__sk_buff, tstamp)),
977            scalar_u32_field(offset_of!(__sk_buff, gso_segs)),
978            scalar_u32_field(offset_of!(__sk_buff, gso_size)),
979        ],
980    )
981});
982pub static SOCKET_FILTER_ARGS: LazyLock<Vec<Type>> =
983    LazyLock::new(|| vec![SOCKET_FILTER_SK_BUF_TYPE.clone()]);
984
985/// Type for the `__sk_buff` passed to `BPF_PROG_TYPE_SCHED_CLS` and
986/// `BPF_PROG_TYPE_SCHED_ACT` programs.
987pub static SCHED_ARG_TYPE: LazyLock<Type> = LazyLock::new(|| {
988    let data_id = MemoryId::new();
989    ptr_to_struct_type(
990        SK_BUF_ID.clone(),
991        vec![
992            // All fields from the start of `__sk_buff` to `cb` are read-only scalars, except mark
993            // that is read-write.
994            scalar_range(0, offset_of!(__sk_buff, mark)),
995            scalar_u32_mut_field(offset_of!(__sk_buff, mark)),
996            scalar_range(offset_of!(__sk_buff, queue_mapping), offset_of!(__sk_buff, cb)),
997            // `cb` is a mutable array.
998            scalar_mut_range(offset_of!(__sk_buff, cb), offset_of!(__sk_buff, hash)),
999            scalar_u32_field(offset_of!(__sk_buff, hash)),
1000            scalar_u32_field(offset_of!(__sk_buff, tc_classid)),
1001            array_start_32_field(offset_of!(__sk_buff, data), data_id.clone()),
1002            array_end_32_field(offset_of!(__sk_buff, data_end), data_id),
1003            scalar_u32_field(offset_of!(__sk_buff, napi_id)),
1004            scalar_u32_field(offset_of!(__sk_buff, data_meta)),
1005            scalar_range(offset_of!(__sk_buff, tstamp), size_of::<__sk_buff>()),
1006        ],
1007    )
1008});
1009pub static SCHED_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![SCHED_ARG_TYPE.clone()]);
1010
1011/// Type for the `__sk_buff` passed to `BPF_PROG_TYPE_CGROUP_SKB` programs.
1012pub static CGROUP_SKB_SK_BUF_TYPE: LazyLock<Type> = LazyLock::new(|| {
1013    let data_id = MemoryId::new();
1014    assert!(offset_of!(__sk_buff, __bindgen_anon_2) == 168);
1015    ptr_to_struct_type(
1016        SK_BUF_ID.clone(),
1017        vec![
1018            // All fields from the start of `__sk_buff` to `cb` are read-only scalars, except mark
1019            // that is read-write.
1020            scalar_range(0, offset_of!(__sk_buff, mark)),
1021            scalar_u32_mut_field(offset_of!(__sk_buff, mark)),
1022            scalar_range(offset_of!(__sk_buff, queue_mapping), offset_of!(__sk_buff, cb)),
1023            // `cb` is a mutable array.
1024            scalar_mut_range(offset_of!(__sk_buff, cb), offset_of!(__sk_buff, hash)),
1025            scalar_u32_field(offset_of!(__sk_buff, hash)),
1026            array_start_32_field(offset_of!(__sk_buff, data), data_id.clone()),
1027            array_end_32_field(offset_of!(__sk_buff, data_end), data_id),
1028            scalar_range(offset_of!(__sk_buff, napi_id), offset_of!(__sk_buff, data_meta)),
1029            scalar_u64_field(offset_of!(__sk_buff, tstamp)),
1030            scalar_u32_field(offset_of!(__sk_buff, gso_segs)),
1031            // `sk` field
1032            nullable_ptr_to_mem_field::<bpf_sock>(
1033                offset_of!(__sk_buff, __bindgen_anon_2),
1034                BPF_SOCK_ID.clone(),
1035            ),
1036            scalar_u32_field(offset_of!(__sk_buff, gso_size)),
1037            scalar_u64_field(offset_of!(__sk_buff, hwtstamp)),
1038        ],
1039    )
1040});
1041pub static CGROUP_SKB_ARGS: LazyLock<Vec<Type>> =
1042    LazyLock::new(|| vec![CGROUP_SKB_SK_BUF_TYPE.clone()]);
1043
1044static XDP_MD_ID: MemoryId = StructId::XdpMd.as_memory_id();
1045static XDP_MD_TYPE: LazyLock<Type> = LazyLock::new(|| {
1046    let data_id = MemoryId::new();
1047
1048    ptr_to_struct_type(
1049        XDP_MD_ID.clone(),
1050        vec![
1051            array_start_32_field(offset_of!(xdp_md, data), data_id.clone()),
1052            array_end_32_field(offset_of!(xdp_md, data_end), data_id),
1053            // All fields starting from `data_meta` are readable.
1054            {
1055                let data_meta_offset = offset_of!(xdp_md, data_meta);
1056                scalar_field(data_meta_offset, std::mem::size_of::<xdp_md>() - data_meta_offset)
1057            },
1058        ],
1059    )
1060});
1061static XDP_MD_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![XDP_MD_TYPE.clone()]);
1062
1063pub static BPF_USER_PT_REGS_T_ID: MemoryId = StructId::BpfUserPtRegs.as_memory_id();
1064pub static BPF_USER_PT_REGS_T_ARGS: LazyLock<Vec<Type>> =
1065    LazyLock::new(|| vec![ptr_to_mem_type::<bpf_user_pt_regs_t>(BPF_USER_PT_REGS_T_ID.clone())]);
1066
1067pub static BPF_SOCK_ID: MemoryId = StructId::BpfSock.as_memory_id();
1068pub static BPF_SOCK_TYPE: LazyLock<Type> =
1069    LazyLock::new(|| ptr_to_mem_type::<bpf_sock>(BPF_SOCK_ID.clone()));
1070pub static BPF_SOCK_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![BPF_SOCK_TYPE.clone()]);
1071
1072pub static BPF_SOCKOPT_ID: MemoryId = StructId::BpfSockOpt.as_memory_id();
1073pub static BPF_SOCKOPT_TYPE: LazyLock<Type> = LazyLock::new(|| {
1074    let optval_id = MemoryId::new();
1075    ptr_to_struct_type(
1076        BPF_SOCKOPT_ID.clone(),
1077        vec![
1078            // sk
1079            ptr_to_mem_field::<bpf_sock>(
1080                offset_of!(bpf_sockopt, __bindgen_anon_1),
1081                BPF_SOCK_ID.clone(),
1082            ),
1083            // optval
1084            array_start_field(offset_of!(bpf_sockopt, __bindgen_anon_2), optval_id.clone()),
1085            // optval_end
1086            array_end_field(offset_of!(bpf_sockopt, __bindgen_anon_3), optval_id),
1087            scalar_u32_field(offset_of!(bpf_sockopt, level)),
1088            scalar_u32_mut_field(offset_of!(bpf_sockopt, optname)),
1089            scalar_u32_mut_field(offset_of!(bpf_sockopt, optlen)),
1090            scalar_u32_mut_field(offset_of!(bpf_sockopt, retval)),
1091        ],
1092    )
1093});
1094pub static BPF_SOCKOPT_ARGS: LazyLock<Vec<Type>> = LazyLock::new(|| vec![BPF_SOCKOPT_TYPE.clone()]);
1095
1096// Verifier allows access only to some fields of the `bfp_sock_addr` struct
1097// depending on the `expected_attach_type` passed when the program is loaded.
1098// The INET4 and INET6 versions defined below should be used by the verifier
1099// for INET4 and INET6 attachments. `BPF_SOCK_ADDR_TYPE` contains all fields
1100// from that struct. It's used by the `ProgramArgument` implementation for
1101// the struct. This allows to share the `EbpfProgramContext` for all programs
1102// that take `bpf_sock_addr`. Linkers considers `BPF_SOCK_ADDR_TYPE` as is
1103// a subtype of both INET4 and INET6 versions.
1104pub static BPF_SOCK_ADDR_ID: MemoryId = StructId::BpfSockAddr.as_memory_id();
1105pub static BPF_SOCK_ADDR_TYPE: LazyLock<Type> = LazyLock::new(|| {
1106    ptr_to_struct_type(
1107        BPF_SOCK_ADDR_ID.clone(),
1108        vec![
1109            scalar_u32_field(offset_of!(bpf_sock_addr, user_family)),
1110            scalar_u32_field(offset_of!(bpf_sock_addr, user_ip4)),
1111            scalar_field(offset_of!(bpf_sock_addr, user_ip6), 16),
1112            scalar_u32_field(offset_of!(bpf_sock_addr, user_port)),
1113            scalar_u32_field(offset_of!(bpf_sock_addr, family)),
1114            scalar_u32_field(offset_of!(bpf_sock_addr, type_)),
1115            scalar_u32_field(offset_of!(bpf_sock_addr, protocol)),
1116            scalar_u32_field(offset_of!(bpf_sock_addr, msg_src_ip4)),
1117            scalar_field(offset_of!(bpf_sock_addr, msg_src_ip6), 16),
1118            // sk
1119            ptr_to_mem_field::<bpf_sock>(
1120                offset_of!(bpf_sock_addr, __bindgen_anon_1),
1121                BPF_SOCK_ID.clone(),
1122            ),
1123        ],
1124    )
1125});
1126
1127pub static BPF_SOCK_ADDR_INET4_TYPE: LazyLock<Type> = LazyLock::new(|| {
1128    ptr_to_struct_type(
1129        BPF_SOCK_ADDR_ID.clone(),
1130        vec![
1131            scalar_u32_field(offset_of!(bpf_sock_addr, user_family)),
1132            scalar_u32_field(offset_of!(bpf_sock_addr, user_ip4)),
1133            scalar_u32_field(offset_of!(bpf_sock_addr, user_port)),
1134            scalar_u32_field(offset_of!(bpf_sock_addr, family)),
1135            scalar_u32_field(offset_of!(bpf_sock_addr, type_)),
1136            scalar_u32_field(offset_of!(bpf_sock_addr, protocol)),
1137            // sk
1138            ptr_to_mem_field::<bpf_sock>(
1139                offset_of!(bpf_sock_addr, __bindgen_anon_1),
1140                BPF_SOCK_ID.clone(),
1141            ),
1142        ],
1143    )
1144});
1145pub static BPF_SOCK_ADDR_INET4_ARGS: LazyLock<Vec<Type>> =
1146    LazyLock::new(|| vec![BPF_SOCK_ADDR_INET4_TYPE.clone()]);
1147
1148pub static BPF_SOCK_ADDR_INET6_TYPE: LazyLock<Type> = LazyLock::new(|| {
1149    ptr_to_struct_type(
1150        BPF_SOCK_ADDR_ID.clone(),
1151        vec![
1152            scalar_u32_field(offset_of!(bpf_sock_addr, user_family)),
1153            scalar_field(offset_of!(bpf_sock_addr, user_ip6), 16),
1154            scalar_u32_field(offset_of!(bpf_sock_addr, user_port)),
1155            scalar_u32_field(offset_of!(bpf_sock_addr, family)),
1156            scalar_u32_field(offset_of!(bpf_sock_addr, type_)),
1157            scalar_u32_field(offset_of!(bpf_sock_addr, protocol)),
1158            // sk
1159            ptr_to_mem_field::<bpf_sock>(
1160                offset_of!(bpf_sock_addr, __bindgen_anon_1),
1161                BPF_SOCK_ID.clone(),
1162            ),
1163        ],
1164    )
1165});
1166pub static BPF_SOCK_ADDR_INET6_ARGS: LazyLock<Vec<Type>> =
1167    LazyLock::new(|| vec![BPF_SOCK_ADDR_INET6_TYPE.clone()]);
1168
1169#[repr(C)]
1170#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
1171struct TraceEntry {
1172    type_: u16,
1173    flags: u8,
1174    preemp_count: u8,
1175    pid: u32,
1176}
1177
1178#[repr(C)]
1179#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
1180struct TraceEvent {
1181    trace_entry: TraceEntry,
1182    id: u64,
1183    // This is defined a being big enough for all expected tracepoint. It is not clear how the
1184    // verifier can know which tracepoint is targeted when the program is loaded. Instead, this
1185    // array will be big enough, and will be filled with 0 when running a given program.
1186    args: [u64; 16],
1187}
1188
1189#[repr(C)]
1190#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
1191struct RawTraceEvent {
1192    // This is defined a being big enough for all expected tracepoint. It is not clear how the
1193    // verifier can know which tracepoint is targeted when the program is loaded. Instead, this
1194    // array will be big enough, and will be filled with 0 when running a given program.
1195    args: [u64; 2],
1196}
1197
1198static BPF_TRACEPOINT_ID: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
1199static BPF_TRACEPOINT_ARGS: LazyLock<Vec<Type>> =
1200    LazyLock::new(|| vec![ptr_to_mem_type::<TraceEvent>(BPF_TRACEPOINT_ID.clone())]);
1201
1202static BPF_RAW_TRACEPOINT_ID: LazyLock<MemoryId> = LazyLock::new(MemoryId::new);
1203static BPF_RAW_TRACEPOINT_ARGS: LazyLock<Vec<Type>> =
1204    LazyLock::new(|| vec![ptr_to_mem_type::<RawTraceEvent>(BPF_RAW_TRACEPOINT_ID.clone())]);
1205
1206/// The different type of BPF programs.
1207#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1208pub enum ProgramType {
1209    CgroupDevice,
1210    CgroupSkb,
1211    CgroupSock,
1212    CgroupSockAddr,
1213    CgroupSockopt,
1214    CgroupSysctl,
1215    Ext,
1216    FlowDissector,
1217    Kprobe,
1218    LircMode2,
1219    Lsm,
1220    LwtIn,
1221    LwtOut,
1222    LwtSeg6Local,
1223    LwtXmit,
1224    Netfilter,
1225    PerfEvent,
1226    RawTracepoint,
1227    RawTracepointWritable,
1228    SchedAct,
1229    SchedCls,
1230    SkLookup,
1231    SkMsg,
1232    SkReuseport,
1233    SkSkb,
1234    SocketFilter,
1235    SockOps,
1236    StructOps,
1237    Syscall,
1238    Tracepoint,
1239    Tracing,
1240    Unspec,
1241    Xdp,
1242}
1243
1244#[derive(thiserror::Error, Debug, PartialEq, Eq)]
1245pub enum EbpfApiError {
1246    #[error("Invalid program type: 0x{0:x}")]
1247    InvalidProgramType(u32),
1248
1249    #[error("Unsupported program type: {0:?}")]
1250    UnsupportedProgramType(ProgramType),
1251
1252    #[error("Invalid expected_attach_type: 0x{0:?}")]
1253    InvalidExpectedAttachType(AttachType),
1254}
1255
1256impl TryFrom<u32> for ProgramType {
1257    type Error = EbpfApiError;
1258
1259    fn try_from(program_type: u32) -> Result<Self, Self::Error> {
1260        match program_type {
1261            #![allow(non_upper_case_globals)]
1262            bpf_prog_type_BPF_PROG_TYPE_CGROUP_DEVICE => Ok(Self::CgroupDevice),
1263            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SKB => Ok(Self::CgroupSkb),
1264            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK => Ok(Self::CgroupSock),
1265            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK_ADDR => Ok(Self::CgroupSockAddr),
1266            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCKOPT => Ok(Self::CgroupSockopt),
1267            bpf_prog_type_BPF_PROG_TYPE_CGROUP_SYSCTL => Ok(Self::CgroupSysctl),
1268            bpf_prog_type_BPF_PROG_TYPE_EXT => Ok(Self::Ext),
1269            bpf_prog_type_BPF_PROG_TYPE_FLOW_DISSECTOR => Ok(Self::FlowDissector),
1270            bpf_prog_type_BPF_PROG_TYPE_KPROBE => Ok(Self::Kprobe),
1271            bpf_prog_type_BPF_PROG_TYPE_LIRC_MODE2 => Ok(Self::LircMode2),
1272            bpf_prog_type_BPF_PROG_TYPE_LSM => Ok(Self::Lsm),
1273            bpf_prog_type_BPF_PROG_TYPE_LWT_IN => Ok(Self::LwtIn),
1274            bpf_prog_type_BPF_PROG_TYPE_LWT_OUT => Ok(Self::LwtOut),
1275            bpf_prog_type_BPF_PROG_TYPE_LWT_SEG6LOCAL => Ok(Self::LwtSeg6Local),
1276            bpf_prog_type_BPF_PROG_TYPE_LWT_XMIT => Ok(Self::LwtXmit),
1277            bpf_prog_type_BPF_PROG_TYPE_NETFILTER => Ok(Self::Netfilter),
1278            bpf_prog_type_BPF_PROG_TYPE_PERF_EVENT => Ok(Self::PerfEvent),
1279            bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT => Ok(Self::RawTracepoint),
1280            bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE => Ok(Self::RawTracepointWritable),
1281            bpf_prog_type_BPF_PROG_TYPE_SCHED_ACT => Ok(Self::SchedAct),
1282            bpf_prog_type_BPF_PROG_TYPE_SCHED_CLS => Ok(Self::SchedCls),
1283            bpf_prog_type_BPF_PROG_TYPE_SK_LOOKUP => Ok(Self::SkLookup),
1284            bpf_prog_type_BPF_PROG_TYPE_SK_MSG => Ok(Self::SkMsg),
1285            bpf_prog_type_BPF_PROG_TYPE_SK_REUSEPORT => Ok(Self::SkReuseport),
1286            bpf_prog_type_BPF_PROG_TYPE_SK_SKB => Ok(Self::SkSkb),
1287            bpf_prog_type_BPF_PROG_TYPE_SOCK_OPS => Ok(Self::SockOps),
1288            bpf_prog_type_BPF_PROG_TYPE_SOCKET_FILTER => Ok(Self::SocketFilter),
1289            bpf_prog_type_BPF_PROG_TYPE_STRUCT_OPS => Ok(Self::StructOps),
1290            bpf_prog_type_BPF_PROG_TYPE_SYSCALL => Ok(Self::Syscall),
1291            bpf_prog_type_BPF_PROG_TYPE_TRACEPOINT => Ok(Self::Tracepoint),
1292            bpf_prog_type_BPF_PROG_TYPE_TRACING => Ok(Self::Tracing),
1293            bpf_prog_type_BPF_PROG_TYPE_UNSPEC => Ok(Self::Unspec),
1294            bpf_prog_type_BPF_PROG_TYPE_XDP => Ok(Self::Xdp),
1295            program_type @ _ => Err(EbpfApiError::InvalidProgramType(program_type)),
1296        }
1297    }
1298}
1299
1300impl From<ProgramType> for u32 {
1301    fn from(program_type: ProgramType) -> u32 {
1302        match program_type {
1303            ProgramType::CgroupDevice => bpf_prog_type_BPF_PROG_TYPE_CGROUP_DEVICE,
1304            ProgramType::CgroupSkb => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SKB,
1305            ProgramType::CgroupSock => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK,
1306            ProgramType::CgroupSockAddr => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
1307            ProgramType::CgroupSockopt => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SOCKOPT,
1308            ProgramType::CgroupSysctl => bpf_prog_type_BPF_PROG_TYPE_CGROUP_SYSCTL,
1309            ProgramType::Ext => bpf_prog_type_BPF_PROG_TYPE_EXT,
1310            ProgramType::FlowDissector => bpf_prog_type_BPF_PROG_TYPE_FLOW_DISSECTOR,
1311            ProgramType::Kprobe => bpf_prog_type_BPF_PROG_TYPE_KPROBE,
1312            ProgramType::LircMode2 => bpf_prog_type_BPF_PROG_TYPE_LIRC_MODE2,
1313            ProgramType::Lsm => bpf_prog_type_BPF_PROG_TYPE_LSM,
1314            ProgramType::LwtIn => bpf_prog_type_BPF_PROG_TYPE_LWT_IN,
1315            ProgramType::LwtOut => bpf_prog_type_BPF_PROG_TYPE_LWT_OUT,
1316            ProgramType::LwtSeg6Local => bpf_prog_type_BPF_PROG_TYPE_LWT_SEG6LOCAL,
1317            ProgramType::LwtXmit => bpf_prog_type_BPF_PROG_TYPE_LWT_XMIT,
1318            ProgramType::Netfilter => bpf_prog_type_BPF_PROG_TYPE_NETFILTER,
1319            ProgramType::PerfEvent => bpf_prog_type_BPF_PROG_TYPE_PERF_EVENT,
1320            ProgramType::RawTracepoint => bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT,
1321            ProgramType::RawTracepointWritable => {
1322                bpf_prog_type_BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
1323            }
1324            ProgramType::SchedAct => bpf_prog_type_BPF_PROG_TYPE_SCHED_ACT,
1325            ProgramType::SchedCls => bpf_prog_type_BPF_PROG_TYPE_SCHED_CLS,
1326            ProgramType::SkLookup => bpf_prog_type_BPF_PROG_TYPE_SK_LOOKUP,
1327            ProgramType::SkMsg => bpf_prog_type_BPF_PROG_TYPE_SK_MSG,
1328            ProgramType::SkReuseport => bpf_prog_type_BPF_PROG_TYPE_SK_REUSEPORT,
1329            ProgramType::SkSkb => bpf_prog_type_BPF_PROG_TYPE_SK_SKB,
1330            ProgramType::SockOps => bpf_prog_type_BPF_PROG_TYPE_SOCK_OPS,
1331            ProgramType::SocketFilter => bpf_prog_type_BPF_PROG_TYPE_SOCKET_FILTER,
1332            ProgramType::StructOps => bpf_prog_type_BPF_PROG_TYPE_STRUCT_OPS,
1333            ProgramType::Syscall => bpf_prog_type_BPF_PROG_TYPE_SYSCALL,
1334            ProgramType::Tracepoint => bpf_prog_type_BPF_PROG_TYPE_TRACEPOINT,
1335            ProgramType::Tracing => bpf_prog_type_BPF_PROG_TYPE_TRACING,
1336            ProgramType::Unspec => bpf_prog_type_BPF_PROG_TYPE_UNSPEC,
1337            ProgramType::Xdp => bpf_prog_type_BPF_PROG_TYPE_XDP,
1338        }
1339    }
1340}
1341
1342impl ProgramType {
1343    pub fn get_helpers(self) -> HashMap<u32, &'static HelperDefinition> {
1344        BPF_HELPERS_DEFINITIONS
1345            .iter()
1346            .filter_map(|(filter, helper)| filter.accept(self).then_some((helper.index, helper)))
1347            .collect()
1348    }
1349
1350    pub fn get_args(
1351        self,
1352        expected_attach_type: AttachType,
1353    ) -> Result<&'static [Type], EbpfApiError> {
1354        let args = match self {
1355            Self::SocketFilter => &SOCKET_FILTER_ARGS,
1356            Self::SchedAct | Self::SchedCls => &SCHED_ARGS,
1357            Self::CgroupSkb => match expected_attach_type {
1358                AttachType::Unspecified
1359                | AttachType::CgroupInetIngress
1360                | AttachType::CgroupInetEgress => &CGROUP_SKB_ARGS,
1361                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1362            },
1363
1364            Self::Xdp => &XDP_MD_ARGS,
1365            Self::Kprobe => &BPF_USER_PT_REGS_T_ARGS,
1366            Self::Tracepoint => &BPF_TRACEPOINT_ARGS,
1367            Self::RawTracepoint => &BPF_RAW_TRACEPOINT_ARGS,
1368
1369            Self::CgroupSock => match expected_attach_type {
1370                AttachType::Unspecified
1371                | AttachType::CgroupInetIngress
1372                | AttachType::CgroupInetSockCreate
1373                | AttachType::CgroupInet4PostBind
1374                | AttachType::CgroupInet6PostBind
1375                | AttachType::CgroupInetSockRelease => &BPF_SOCK_ARGS,
1376                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1377            },
1378
1379            Self::CgroupSockopt => match expected_attach_type {
1380                AttachType::CgroupGetsockopt | AttachType::CgroupSetsockopt => &BPF_SOCKOPT_ARGS,
1381                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1382            },
1383
1384            Self::CgroupSockAddr => match expected_attach_type {
1385                AttachType::CgroupInet4Bind
1386                | AttachType::CgroupInet4Connect
1387                | AttachType::CgroupUdp4Sendmsg
1388                | AttachType::CgroupUdp4Recvmsg
1389                | AttachType::CgroupInet4Getpeername
1390                | AttachType::CgroupInet4Getsockname => &BPF_SOCK_ADDR_INET4_ARGS,
1391
1392                AttachType::CgroupInet6Bind
1393                | AttachType::CgroupInet6Connect
1394                | AttachType::CgroupUdp6Sendmsg
1395                | AttachType::CgroupUdp6Recvmsg
1396                | AttachType::CgroupInet6Getpeername
1397                | AttachType::CgroupInet6Getsockname => &BPF_SOCK_ADDR_INET6_ARGS,
1398
1399                _ => return Err(EbpfApiError::InvalidExpectedAttachType(expected_attach_type)),
1400            },
1401
1402            Self::CgroupDevice
1403            | Self::CgroupSysctl
1404            | Self::Ext
1405            | Self::FlowDissector
1406            | Self::LircMode2
1407            | Self::Lsm
1408            | Self::LwtIn
1409            | Self::LwtOut
1410            | Self::LwtSeg6Local
1411            | Self::LwtXmit
1412            | Self::Netfilter
1413            | Self::PerfEvent
1414            | Self::RawTracepointWritable
1415            | Self::SkLookup
1416            | Self::SkMsg
1417            | Self::SkReuseport
1418            | Self::SkSkb
1419            | Self::SockOps
1420            | Self::StructOps
1421            | Self::Syscall
1422            | Self::Tracing
1423            | Self::Unspec => return Err(EbpfApiError::UnsupportedProgramType(self)),
1424        };
1425        Ok(args)
1426    }
1427
1428    pub fn create_calling_context(
1429        self,
1430        expected_attach_type: AttachType,
1431        maps: Vec<MapSchema>,
1432    ) -> Result<CallingContext, EbpfApiError> {
1433        let args = self.get_args(expected_attach_type)?.to_vec();
1434        let packet_type = match self {
1435            Self::SocketFilter => Some(SOCKET_FILTER_SK_BUF_TYPE.clone()),
1436            Self::SchedAct | Self::SchedCls => Some(SCHED_ARG_TYPE.clone()),
1437            _ => None,
1438        };
1439        Ok(CallingContext { maps, helpers: self.get_helpers(), args, packet_type })
1440    }
1441}
1442
1443#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1444pub enum AttachType {
1445    CgroupInetIngress,
1446    CgroupInetEgress,
1447    CgroupInetSockCreate,
1448    CgroupSockOps,
1449    SkSkbStreamParser,
1450    SkSkbStreamVerdict,
1451    CgroupDevice,
1452    SkMsgVerdict,
1453    CgroupInet4Bind,
1454    CgroupInet6Bind,
1455    CgroupInet4Connect,
1456    CgroupInet6Connect,
1457    CgroupInet4PostBind,
1458    CgroupInet6PostBind,
1459    CgroupUdp4Sendmsg,
1460    CgroupUdp6Sendmsg,
1461    LircMode2,
1462    FlowDissector,
1463    CgroupSysctl,
1464    CgroupUdp4Recvmsg,
1465    CgroupUdp6Recvmsg,
1466    CgroupGetsockopt,
1467    CgroupSetsockopt,
1468    TraceRawTp,
1469    TraceFentry,
1470    TraceFexit,
1471    ModifyReturn,
1472    LsmMac,
1473    TraceIter,
1474    CgroupInet4Getpeername,
1475    CgroupInet6Getpeername,
1476    CgroupInet4Getsockname,
1477    CgroupInet6Getsockname,
1478    XdpDevmap,
1479    CgroupInetSockRelease,
1480    XdpCpumap,
1481    SkLookup,
1482    Xdp,
1483    SkSkbVerdict,
1484    SkReuseportSelect,
1485    SkReuseportSelectOrMigrate,
1486    PerfEvent,
1487    TraceKprobeMulti,
1488    LsmCgroup,
1489    StructOps,
1490    Netfilter,
1491    TcxIngress,
1492    TcxEgress,
1493    TraceUprobeMulti,
1494    CgroupUnixConnect,
1495    CgroupUnixSendmsg,
1496    CgroupUnixRecvmsg,
1497    CgroupUnixGetpeername,
1498    CgroupUnixGetsockname,
1499    NetkitPrimary,
1500    NetkitPeer,
1501    TraceKprobeSession,
1502
1503    // Corresponds to `attach_type=-1`. Linux allows this value in
1504    // `expected_attach_type` for some `program_types`
1505    Unspecified,
1506
1507    // Corresponds to any `attach_type` value other than -1 and
1508    // `bpf_attach_type` enum values.
1509    Invalid(u32),
1510}
1511
1512impl From<u32> for AttachType {
1513    fn from(attach_type: u32) -> Self {
1514        match attach_type {
1515            #![allow(non_upper_case_globals)]
1516            bpf_attach_type_BPF_CGROUP_INET_INGRESS => Self::CgroupInetIngress,
1517            bpf_attach_type_BPF_CGROUP_INET_EGRESS => Self::CgroupInetEgress,
1518            bpf_attach_type_BPF_CGROUP_INET_SOCK_CREATE => Self::CgroupInetSockCreate,
1519            bpf_attach_type_BPF_CGROUP_SOCK_OPS => Self::CgroupSockOps,
1520            bpf_attach_type_BPF_SK_SKB_STREAM_PARSER => Self::SkSkbStreamParser,
1521            bpf_attach_type_BPF_SK_SKB_STREAM_VERDICT => Self::SkSkbStreamVerdict,
1522            bpf_attach_type_BPF_CGROUP_DEVICE => Self::CgroupDevice,
1523            bpf_attach_type_BPF_SK_MSG_VERDICT => Self::SkMsgVerdict,
1524            bpf_attach_type_BPF_CGROUP_INET4_BIND => Self::CgroupInet4Bind,
1525            bpf_attach_type_BPF_CGROUP_INET6_BIND => Self::CgroupInet6Bind,
1526            bpf_attach_type_BPF_CGROUP_INET4_CONNECT => Self::CgroupInet4Connect,
1527            bpf_attach_type_BPF_CGROUP_INET6_CONNECT => Self::CgroupInet6Connect,
1528            bpf_attach_type_BPF_CGROUP_INET4_POST_BIND => Self::CgroupInet4PostBind,
1529            bpf_attach_type_BPF_CGROUP_INET6_POST_BIND => Self::CgroupInet6PostBind,
1530            bpf_attach_type_BPF_CGROUP_UDP4_SENDMSG => Self::CgroupUdp4Sendmsg,
1531            bpf_attach_type_BPF_CGROUP_UDP6_SENDMSG => Self::CgroupUdp6Sendmsg,
1532            bpf_attach_type_BPF_LIRC_MODE2 => Self::LircMode2,
1533            bpf_attach_type_BPF_FLOW_DISSECTOR => Self::FlowDissector,
1534            bpf_attach_type_BPF_CGROUP_SYSCTL => Self::CgroupSysctl,
1535            bpf_attach_type_BPF_CGROUP_UDP4_RECVMSG => Self::CgroupUdp4Recvmsg,
1536            bpf_attach_type_BPF_CGROUP_UDP6_RECVMSG => Self::CgroupUdp6Recvmsg,
1537            bpf_attach_type_BPF_CGROUP_GETSOCKOPT => Self::CgroupGetsockopt,
1538            bpf_attach_type_BPF_CGROUP_SETSOCKOPT => Self::CgroupSetsockopt,
1539            bpf_attach_type_BPF_TRACE_RAW_TP => Self::TraceRawTp,
1540            bpf_attach_type_BPF_TRACE_FENTRY => Self::TraceFentry,
1541            bpf_attach_type_BPF_TRACE_FEXIT => Self::TraceFexit,
1542            bpf_attach_type_BPF_MODIFY_RETURN => Self::ModifyReturn,
1543            bpf_attach_type_BPF_LSM_MAC => Self::LsmMac,
1544            bpf_attach_type_BPF_TRACE_ITER => Self::TraceIter,
1545            bpf_attach_type_BPF_CGROUP_INET4_GETPEERNAME => Self::CgroupInet4Getpeername,
1546            bpf_attach_type_BPF_CGROUP_INET6_GETPEERNAME => Self::CgroupInet6Getpeername,
1547            bpf_attach_type_BPF_CGROUP_INET4_GETSOCKNAME => Self::CgroupInet4Getsockname,
1548            bpf_attach_type_BPF_CGROUP_INET6_GETSOCKNAME => Self::CgroupInet6Getsockname,
1549            bpf_attach_type_BPF_XDP_DEVMAP => Self::XdpDevmap,
1550            bpf_attach_type_BPF_CGROUP_INET_SOCK_RELEASE => Self::CgroupInetSockRelease,
1551            bpf_attach_type_BPF_XDP_CPUMAP => Self::XdpCpumap,
1552            bpf_attach_type_BPF_SK_LOOKUP => Self::SkLookup,
1553            bpf_attach_type_BPF_XDP => Self::Xdp,
1554            bpf_attach_type_BPF_SK_SKB_VERDICT => Self::SkSkbVerdict,
1555            bpf_attach_type_BPF_SK_REUSEPORT_SELECT => Self::SkReuseportSelect,
1556            bpf_attach_type_BPF_SK_REUSEPORT_SELECT_OR_MIGRATE => Self::SkReuseportSelectOrMigrate,
1557            bpf_attach_type_BPF_PERF_EVENT => Self::PerfEvent,
1558            bpf_attach_type_BPF_TRACE_KPROBE_MULTI => Self::TraceKprobeMulti,
1559            bpf_attach_type_BPF_LSM_CGROUP => Self::LsmCgroup,
1560            bpf_attach_type_BPF_STRUCT_OPS => Self::StructOps,
1561            bpf_attach_type_BPF_NETFILTER => Self::Netfilter,
1562            bpf_attach_type_BPF_TCX_INGRESS => Self::TcxIngress,
1563            bpf_attach_type_BPF_TCX_EGRESS => Self::TcxEgress,
1564            bpf_attach_type_BPF_TRACE_UPROBE_MULTI => Self::TraceUprobeMulti,
1565            bpf_attach_type_BPF_CGROUP_UNIX_CONNECT => Self::CgroupUnixConnect,
1566            bpf_attach_type_BPF_CGROUP_UNIX_SENDMSG => Self::CgroupUnixSendmsg,
1567            bpf_attach_type_BPF_CGROUP_UNIX_RECVMSG => Self::CgroupUnixRecvmsg,
1568            bpf_attach_type_BPF_CGROUP_UNIX_GETPEERNAME => Self::CgroupUnixGetpeername,
1569            bpf_attach_type_BPF_CGROUP_UNIX_GETSOCKNAME => Self::CgroupUnixGetsockname,
1570            bpf_attach_type_BPF_NETKIT_PRIMARY => Self::NetkitPrimary,
1571            bpf_attach_type_BPF_NETKIT_PEER => Self::NetkitPeer,
1572            bpf_attach_type_BPF_TRACE_KPROBE_SESSION => Self::TraceKprobeSession,
1573
1574            u32::MAX => Self::Unspecified,
1575            _ => Self::Invalid(attach_type),
1576        }
1577    }
1578}
1579
1580impl From<AttachType> for u32 {
1581    fn from(attach_type: AttachType) -> Self {
1582        match attach_type {
1583            AttachType::CgroupInetIngress => bpf_attach_type_BPF_CGROUP_INET_INGRESS,
1584            AttachType::CgroupInetEgress => bpf_attach_type_BPF_CGROUP_INET_EGRESS,
1585            AttachType::CgroupInetSockCreate => bpf_attach_type_BPF_CGROUP_INET_SOCK_CREATE,
1586            AttachType::CgroupSockOps => bpf_attach_type_BPF_CGROUP_SOCK_OPS,
1587            AttachType::SkSkbStreamParser => bpf_attach_type_BPF_SK_SKB_STREAM_PARSER,
1588            AttachType::SkSkbStreamVerdict => bpf_attach_type_BPF_SK_SKB_STREAM_VERDICT,
1589            AttachType::CgroupDevice => bpf_attach_type_BPF_CGROUP_DEVICE,
1590            AttachType::SkMsgVerdict => bpf_attach_type_BPF_SK_MSG_VERDICT,
1591            AttachType::CgroupInet4Bind => bpf_attach_type_BPF_CGROUP_INET4_BIND,
1592            AttachType::CgroupInet6Bind => bpf_attach_type_BPF_CGROUP_INET6_BIND,
1593            AttachType::CgroupInet4Connect => bpf_attach_type_BPF_CGROUP_INET4_CONNECT,
1594            AttachType::CgroupInet6Connect => bpf_attach_type_BPF_CGROUP_INET6_CONNECT,
1595            AttachType::CgroupInet4PostBind => bpf_attach_type_BPF_CGROUP_INET4_POST_BIND,
1596            AttachType::CgroupInet6PostBind => bpf_attach_type_BPF_CGROUP_INET6_POST_BIND,
1597            AttachType::CgroupUdp4Sendmsg => bpf_attach_type_BPF_CGROUP_UDP4_SENDMSG,
1598            AttachType::CgroupUdp6Sendmsg => bpf_attach_type_BPF_CGROUP_UDP6_SENDMSG,
1599            AttachType::LircMode2 => bpf_attach_type_BPF_LIRC_MODE2,
1600            AttachType::FlowDissector => bpf_attach_type_BPF_FLOW_DISSECTOR,
1601            AttachType::CgroupSysctl => bpf_attach_type_BPF_CGROUP_SYSCTL,
1602            AttachType::CgroupUdp4Recvmsg => bpf_attach_type_BPF_CGROUP_UDP4_RECVMSG,
1603            AttachType::CgroupUdp6Recvmsg => bpf_attach_type_BPF_CGROUP_UDP6_RECVMSG,
1604            AttachType::CgroupGetsockopt => bpf_attach_type_BPF_CGROUP_GETSOCKOPT,
1605            AttachType::CgroupSetsockopt => bpf_attach_type_BPF_CGROUP_SETSOCKOPT,
1606            AttachType::TraceRawTp => bpf_attach_type_BPF_TRACE_RAW_TP,
1607            AttachType::TraceFentry => bpf_attach_type_BPF_TRACE_FENTRY,
1608            AttachType::TraceFexit => bpf_attach_type_BPF_TRACE_FEXIT,
1609            AttachType::ModifyReturn => bpf_attach_type_BPF_MODIFY_RETURN,
1610            AttachType::LsmMac => bpf_attach_type_BPF_LSM_MAC,
1611            AttachType::TraceIter => bpf_attach_type_BPF_TRACE_ITER,
1612            AttachType::CgroupInet4Getpeername => bpf_attach_type_BPF_CGROUP_INET4_GETPEERNAME,
1613            AttachType::CgroupInet6Getpeername => bpf_attach_type_BPF_CGROUP_INET6_GETPEERNAME,
1614            AttachType::CgroupInet4Getsockname => bpf_attach_type_BPF_CGROUP_INET4_GETSOCKNAME,
1615            AttachType::CgroupInet6Getsockname => bpf_attach_type_BPF_CGROUP_INET6_GETSOCKNAME,
1616            AttachType::XdpDevmap => bpf_attach_type_BPF_XDP_DEVMAP,
1617            AttachType::CgroupInetSockRelease => bpf_attach_type_BPF_CGROUP_INET_SOCK_RELEASE,
1618            AttachType::XdpCpumap => bpf_attach_type_BPF_XDP_CPUMAP,
1619            AttachType::SkLookup => bpf_attach_type_BPF_SK_LOOKUP,
1620            AttachType::Xdp => bpf_attach_type_BPF_XDP,
1621            AttachType::SkSkbVerdict => bpf_attach_type_BPF_SK_SKB_VERDICT,
1622            AttachType::SkReuseportSelect => bpf_attach_type_BPF_SK_REUSEPORT_SELECT,
1623            AttachType::SkReuseportSelectOrMigrate => {
1624                bpf_attach_type_BPF_SK_REUSEPORT_SELECT_OR_MIGRATE
1625            }
1626            AttachType::PerfEvent => bpf_attach_type_BPF_PERF_EVENT,
1627            AttachType::TraceKprobeMulti => bpf_attach_type_BPF_TRACE_KPROBE_MULTI,
1628            AttachType::LsmCgroup => bpf_attach_type_BPF_LSM_CGROUP,
1629            AttachType::StructOps => bpf_attach_type_BPF_STRUCT_OPS,
1630            AttachType::Netfilter => bpf_attach_type_BPF_NETFILTER,
1631            AttachType::TcxIngress => bpf_attach_type_BPF_TCX_INGRESS,
1632            AttachType::TcxEgress => bpf_attach_type_BPF_TCX_EGRESS,
1633            AttachType::TraceUprobeMulti => bpf_attach_type_BPF_TRACE_UPROBE_MULTI,
1634            AttachType::CgroupUnixConnect => bpf_attach_type_BPF_CGROUP_UNIX_CONNECT,
1635            AttachType::CgroupUnixSendmsg => bpf_attach_type_BPF_CGROUP_UNIX_SENDMSG,
1636            AttachType::CgroupUnixRecvmsg => bpf_attach_type_BPF_CGROUP_UNIX_RECVMSG,
1637            AttachType::CgroupUnixGetpeername => bpf_attach_type_BPF_CGROUP_UNIX_GETPEERNAME,
1638            AttachType::CgroupUnixGetsockname => bpf_attach_type_BPF_CGROUP_UNIX_GETSOCKNAME,
1639            AttachType::NetkitPrimary => bpf_attach_type_BPF_NETKIT_PRIMARY,
1640            AttachType::NetkitPeer => bpf_attach_type_BPF_NETKIT_PEER,
1641            AttachType::TraceKprobeSession => bpf_attach_type_BPF_TRACE_KPROBE_SESSION,
1642            AttachType::Unspecified => u32::MAX,
1643            AttachType::Invalid(attach_type) => attach_type,
1644        }
1645    }
1646}
1647
1648impl From<AttachType> for u64 {
1649    fn from(attach_type: AttachType) -> Self {
1650        (u32::from(attach_type)).into()
1651    }
1652}
1653
1654impl AttachType {
1655    pub fn is_cgroup(&self) -> bool {
1656        match self {
1657            Self::CgroupInetIngress
1658            | Self::CgroupInetEgress
1659            | Self::CgroupInetSockCreate
1660            | Self::CgroupSockOps
1661            | Self::CgroupDevice
1662            | Self::CgroupInet4Bind
1663            | Self::CgroupInet6Bind
1664            | Self::CgroupInet4Connect
1665            | Self::CgroupInet6Connect
1666            | Self::CgroupInet4PostBind
1667            | Self::CgroupInet6PostBind
1668            | Self::CgroupUdp4Sendmsg
1669            | Self::CgroupUdp6Sendmsg
1670            | Self::CgroupSysctl
1671            | Self::CgroupUdp4Recvmsg
1672            | Self::CgroupUdp6Recvmsg
1673            | Self::CgroupGetsockopt
1674            | Self::CgroupSetsockopt
1675            | Self::CgroupInet4Getpeername
1676            | Self::CgroupInet6Getpeername
1677            | Self::CgroupInet4Getsockname
1678            | Self::CgroupInet6Getsockname
1679            | Self::CgroupInetSockRelease
1680            | Self::CgroupUnixConnect
1681            | Self::CgroupUnixSendmsg
1682            | Self::CgroupUnixRecvmsg
1683            | Self::CgroupUnixGetpeername
1684            | Self::CgroupUnixGetsockname => true,
1685            _ => false,
1686        }
1687    }
1688
1689    pub fn get_program_type(&self) -> ProgramType {
1690        match self {
1691            Self::CgroupInetIngress | Self::CgroupInetEgress => ProgramType::CgroupSkb,
1692            Self::CgroupInetSockCreate
1693            | Self::CgroupInet4PostBind
1694            | Self::CgroupInet6PostBind
1695            | Self::CgroupInetSockRelease => ProgramType::CgroupSock,
1696            Self::CgroupSockOps | Self::CgroupGetsockopt | Self::CgroupSetsockopt => {
1697                ProgramType::CgroupSockopt
1698            }
1699            Self::CgroupDevice => ProgramType::CgroupDevice,
1700            Self::CgroupInet4Bind
1701            | Self::CgroupInet6Bind
1702            | Self::CgroupInet4Connect
1703            | Self::CgroupInet6Connect
1704            | Self::CgroupUdp4Sendmsg
1705            | Self::CgroupUdp6Sendmsg
1706            | Self::CgroupUdp4Recvmsg
1707            | Self::CgroupUdp6Recvmsg
1708            | Self::CgroupInet4Getpeername
1709            | Self::CgroupInet6Getpeername
1710            | Self::CgroupInet4Getsockname
1711            | Self::CgroupInet6Getsockname
1712            | Self::CgroupUnixConnect
1713            | Self::CgroupUnixSendmsg
1714            | Self::CgroupUnixRecvmsg
1715            | Self::CgroupUnixGetpeername
1716            | Self::CgroupUnixGetsockname => ProgramType::CgroupSockAddr,
1717            Self::CgroupSysctl => ProgramType::CgroupSysctl,
1718            Self::FlowDissector => ProgramType::FlowDissector,
1719            Self::LircMode2 => ProgramType::LircMode2,
1720            Self::LsmMac | Self::LsmCgroup => ProgramType::Lsm,
1721            Self::Netfilter => ProgramType::Netfilter,
1722            Self::PerfEvent => ProgramType::PerfEvent,
1723            Self::SkLookup => ProgramType::SkLookup,
1724            Self::SkMsgVerdict | Self::SkSkbVerdict => ProgramType::SkMsg,
1725            Self::SkReuseportSelect | Self::SkReuseportSelectOrMigrate => ProgramType::SkReuseport,
1726            Self::SkSkbStreamParser | Self::SkSkbStreamVerdict => ProgramType::SkSkb,
1727            Self::StructOps => ProgramType::StructOps,
1728            Self::TcxIngress | Self::TcxEgress | Self::NetkitPrimary | Self::NetkitPeer => {
1729                ProgramType::SchedCls
1730            }
1731            Self::TraceKprobeMulti | Self::TraceUprobeMulti | Self::TraceKprobeSession => {
1732                ProgramType::Kprobe
1733            }
1734            Self::TraceRawTp
1735            | Self::TraceFentry
1736            | Self::TraceFexit
1737            | Self::ModifyReturn
1738            | Self::TraceIter => ProgramType::Tracing,
1739            Self::XdpDevmap | Self::XdpCpumap | Self::Xdp => ProgramType::Xdp,
1740            Self::Unspecified | Self::Invalid(_) => ProgramType::Unspec,
1741        }
1742    }
1743
1744    // Returns true if the attachment should allow programs created with the
1745    // specified `expected_attach_type`.
1746    pub fn is_compatible_with_expected_attach_type(self, expected: AttachType) -> bool {
1747        // See https://docs.ebpf.io/linux/syscall/BPF_PROG_LOAD/#expected_attach_type.
1748        match self {
1749            // Egress and Ingress attachments are interchangeable. Also `expected_attach_type=-1` is
1750            // allowed in both cases.
1751            Self::CgroupInetIngress | Self::CgroupInetEgress => matches!(
1752                expected,
1753                Self::Unspecified | Self::CgroupInetIngress | Self::CgroupInetEgress
1754            ),
1755
1756            // These attachments allow `expected_attach_type` to be set to
1757            // -1 or 0 (BPF_CGROUP_INET_INGRESS).
1758            Self::CgroupInetSockCreate | Self::CgroupSockOps => {
1759                self == expected || matches!(expected, Self::Unspecified | Self::CgroupInetIngress)
1760            }
1761
1762            // For these attachments `expected_attach_type` must match.
1763            Self::CgroupGetsockopt
1764            | Self::CgroupInet4Bind
1765            | Self::CgroupInet4Connect
1766            | Self::CgroupInet4Getpeername
1767            | Self::CgroupInet4Getsockname
1768            | Self::CgroupInet4PostBind
1769            | Self::CgroupInet6Bind
1770            | Self::CgroupInet6Connect
1771            | Self::CgroupInet6Getpeername
1772            | Self::CgroupInet6Getsockname
1773            | Self::CgroupInet6PostBind
1774            | Self::CgroupInetSockRelease
1775            | Self::CgroupSetsockopt
1776            | Self::CgroupUdp4Recvmsg
1777            | Self::CgroupUdp4Sendmsg
1778            | Self::CgroupUdp6Recvmsg
1779            | Self::CgroupUdp6Sendmsg
1780            | Self::CgroupUnixConnect
1781            | Self::CgroupUnixGetpeername
1782            | Self::CgroupUnixGetsockname
1783            | Self::CgroupUnixRecvmsg
1784            | Self::CgroupUnixSendmsg => self == expected,
1785
1786            // `expected_attach_type` is ignored for all other attachments.
1787            _ => true,
1788        }
1789    }
1790}
1791
1792// Offset used to access auxiliary packet information in cBPF.
1793pub const SKF_AD_OFF: i32 = linux_uapi::SKF_AD_OFF;
1794pub const SKF_AD_PROTOCOL: i32 = linux_uapi::SKF_AD_PROTOCOL as i32;
1795pub const SKF_AD_PKTTYPE: i32 = linux_uapi::SKF_AD_PKTTYPE as i32;
1796pub const SKF_AD_IFINDEX: i32 = linux_uapi::SKF_AD_IFINDEX as i32;
1797pub const SKF_AD_NLATTR: i32 = linux_uapi::SKF_AD_NLATTR as i32;
1798pub const SKF_AD_NLATTR_NEST: i32 = linux_uapi::SKF_AD_NLATTR_NEST as i32;
1799pub const SKF_AD_MARK: i32 = linux_uapi::SKF_AD_MARK as i32;
1800pub const SKF_AD_QUEUE: i32 = linux_uapi::SKF_AD_QUEUE as i32;
1801pub const SKF_AD_HATYPE: i32 = linux_uapi::SKF_AD_HATYPE as i32;
1802pub const SKF_AD_RXHASH: i32 = linux_uapi::SKF_AD_RXHASH as i32;
1803pub const SKF_AD_CPU: i32 = linux_uapi::SKF_AD_CPU as i32;
1804pub const SKF_AD_ALU_XOR_X: i32 = linux_uapi::SKF_AD_ALU_XOR_X as i32;
1805pub const SKF_AD_VLAN_TAG: i32 = linux_uapi::SKF_AD_VLAN_TAG as i32;
1806pub const SKF_AD_VLAN_TAG_PRESENT: i32 = linux_uapi::SKF_AD_VLAN_TAG_PRESENT as i32;
1807pub const SKF_AD_PAY_OFFSET: i32 = linux_uapi::SKF_AD_PAY_OFFSET as i32;
1808pub const SKF_AD_RANDOM: i32 = linux_uapi::SKF_AD_RANDOM as i32;
1809pub const SKF_AD_VLAN_TPID: i32 = linux_uapi::SKF_AD_VLAN_TPID as i32;
1810pub const SKF_AD_MAX: i32 = linux_uapi::SKF_AD_MAX as i32;
1811
1812// Offset used to reference IP headers in cBPF.
1813pub const SKF_NET_OFF: i32 = linux_uapi::SKF_NET_OFF;
1814
1815// Offset used to reference Ethernet headers in cBPF.
1816pub const SKF_LL_OFF: i32 = linux_uapi::SKF_LL_OFF;
1817
1818pub const SECCOMP_CBPF_CONFIG: CbpfConfig = CbpfConfig {
1819    len: CbpfLenInstruction::Static { len: size_of::<seccomp_data>() as i32 },
1820    allow_msh: false,
1821};
1822
1823pub const SOCKET_FILTER_CBPF_CONFIG: CbpfConfig = CbpfConfig {
1824    len: CbpfLenInstruction::ContextField { offset: offset_of!(__sk_buff, len) as i16 },
1825    allow_msh: true,
1826};
1827
1828#[cfg(test)]
1829mod tests {
1830    use super::*;
1831
1832    #[test]
1833    fn test_invalid_program_type() {
1834        assert_eq!(
1835            ProgramType::try_from(0x77777777),
1836            Err(EbpfApiError::InvalidProgramType(0x77777777))
1837        );
1838        assert_eq!(
1839            ProgramType::try_from(u32::MAX),
1840            Err(EbpfApiError::InvalidProgramType(u32::MAX))
1841        );
1842    }
1843
1844    #[test]
1845    fn test_invalid_struct_id() {
1846        assert_eq!(StructId::try_from(&MemoryId::from_raw(0)), Err(()));
1847        assert_eq!(StructId::try_from(&MemoryId::from_raw(7)), Err(()));
1848        assert_eq!(StructId::try_from(&MemoryId::from_raw(u64::MAX)), Err(()));
1849    }
1850}