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