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