bpfd_api/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright Authors of bpfd
3
4pub mod config;
5pub mod util;
6#[path = "bpfd.v1.rs"]
7#[rustfmt::skip]
8#[allow(clippy::all)]
9pub mod v1;
10use clap::ValueEnum;
11use serde::{Deserialize, Serialize};
12use thiserror::Error;
13use url::ParseError as urlParseError;
14use v1::bytecode_location::Location;
15
16#[derive(Error, Debug)]
17pub enum ParseError {
18    #[error("{program} is not a valid program type")]
19    InvalidProgramType { program: String },
20    #[error("{proceedon} is not a valid proceed-on value")]
21    InvalidProceedOn { proceedon: String },
22    #[error("not a valid direction: {direction}")]
23    InvalidDirection { direction: String },
24    #[error("Failed to Parse bytecode location: {0}")]
25    BytecodeLocationParseFailure(#[source] urlParseError),
26    #[error("Invalid bytecode location: {location}")]
27    InvalidBytecodeLocation { location: String },
28    #[error("Invalid bytecode image pull policy: {pull_policy}")]
29    InvalidBytecodeImagePullPolicy { pull_policy: String },
30    #[error("{probe} is not a valid probe type")]
31    InvalidProbeType { probe: String },
32}
33
34#[derive(ValueEnum, Copy, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
35pub enum ProgramType {
36    Unspec,
37    SocketFilter,
38    Probe, // kprobe, kretprobe, uprobe, uretprobe
39    Tc,
40    SchedAct,
41    Tracepoint,
42    Xdp,
43    PerfEvent,
44    CgroupSkb,
45    CgroupSock,
46    LwtIn,
47    LwtOut,
48    LwtXmit,
49    SockOps,
50    SkSkb,
51    CgroupDevice,
52    SkMsg,
53    RawTracepoint,
54    CgroupSockAddr,
55    LwtSeg6Local,
56    LircMode2,
57    SkReuseport,
58    FlowDissector,
59    CgroupSysctl,
60    RawTracepointWritable,
61    CgroupSockopt,
62    Tracing,
63    StructOps,
64    Ext,
65    Lsm,
66    SkLookup,
67    Syscall,
68}
69
70impl TryFrom<String> for ProgramType {
71    type Error = ParseError;
72
73    fn try_from(value: String) -> Result<Self, Self::Error> {
74        Ok(match value.as_str() {
75            "unspec" => ProgramType::Unspec,
76            "socket_filter" => ProgramType::SocketFilter,
77            "probe" => ProgramType::Probe,
78            "tc" => ProgramType::Tc,
79            "sched_act" => ProgramType::SchedAct,
80            "tracepoint" => ProgramType::Tracepoint,
81            "xdp" => ProgramType::Xdp,
82            "perf_event" => ProgramType::PerfEvent,
83            "cgroup_skb" => ProgramType::CgroupSkb,
84            "cgroup_sock" => ProgramType::CgroupSock,
85            "lwt_in" => ProgramType::LwtIn,
86            "lwt_out" => ProgramType::LwtOut,
87            "lwt_xmit" => ProgramType::LwtXmit,
88            "sock_ops" => ProgramType::SockOps,
89            "sk_skb" => ProgramType::SkSkb,
90            "cgroup_device" => ProgramType::CgroupDevice,
91            "sk_msg" => ProgramType::SkMsg,
92            "raw_tracepoint" => ProgramType::RawTracepoint,
93            "cgroup_sock_addr" => ProgramType::CgroupSockAddr,
94            "lwt_seg6local" => ProgramType::LwtSeg6Local,
95            "lirc_mode2" => ProgramType::LircMode2,
96            "sk_reuseport" => ProgramType::SkReuseport,
97            "flow_dissector" => ProgramType::FlowDissector,
98            "cgroup_sysctl" => ProgramType::CgroupSysctl,
99            "raw_tracepoint_writable" => ProgramType::RawTracepointWritable,
100            "cgroup_sockopt" => ProgramType::CgroupSockopt,
101            "tracing" => ProgramType::Tracing,
102            "struct_ops" => ProgramType::StructOps,
103            "ext" => ProgramType::Ext,
104            "lsm" => ProgramType::Lsm,
105            "sk_lookup" => ProgramType::SkLookup,
106            "syscall" => ProgramType::Syscall,
107            other => {
108                return Err(ParseError::InvalidProgramType {
109                    program: other.to_string(),
110                })
111            }
112        })
113    }
114}
115
116impl TryFrom<u32> for ProgramType {
117    type Error = ParseError;
118
119    fn try_from(value: u32) -> Result<Self, Self::Error> {
120        Ok(match value {
121            0 => ProgramType::Unspec,
122            1 => ProgramType::SocketFilter,
123            2 => ProgramType::Probe,
124            3 => ProgramType::Tc,
125            4 => ProgramType::SchedAct,
126            5 => ProgramType::Tracepoint,
127            6 => ProgramType::Xdp,
128            7 => ProgramType::PerfEvent,
129            8 => ProgramType::CgroupSkb,
130            9 => ProgramType::CgroupSock,
131            10 => ProgramType::LwtIn,
132            11 => ProgramType::LwtOut,
133            12 => ProgramType::LwtXmit,
134            13 => ProgramType::SockOps,
135            14 => ProgramType::SkSkb,
136            15 => ProgramType::CgroupDevice,
137            16 => ProgramType::SkMsg,
138            17 => ProgramType::RawTracepoint,
139            18 => ProgramType::CgroupSockAddr,
140            19 => ProgramType::LwtSeg6Local,
141            20 => ProgramType::LircMode2,
142            21 => ProgramType::SkReuseport,
143            22 => ProgramType::FlowDissector,
144            23 => ProgramType::CgroupSysctl,
145            24 => ProgramType::RawTracepointWritable,
146            25 => ProgramType::CgroupSockopt,
147            26 => ProgramType::Tracing,
148            27 => ProgramType::StructOps,
149            28 => ProgramType::Ext,
150            29 => ProgramType::Lsm,
151            30 => ProgramType::SkLookup,
152            31 => ProgramType::Syscall,
153            other => {
154                return Err(ParseError::InvalidProgramType {
155                    program: other.to_string(),
156                })
157            }
158        })
159    }
160}
161
162impl std::fmt::Display for ProgramType {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        let v = match self {
165            ProgramType::Unspec => "unspec",
166            ProgramType::SocketFilter => "socket_filter",
167            ProgramType::Probe => "probe",
168            ProgramType::Tc => "tc",
169            ProgramType::SchedAct => "sched_act",
170            ProgramType::Tracepoint => "tracepoint",
171            ProgramType::Xdp => "xdp",
172            ProgramType::PerfEvent => "perf_event",
173            ProgramType::CgroupSkb => "cgroup_skb",
174            ProgramType::CgroupSock => "cgroup_sock",
175            ProgramType::LwtIn => "lwt_in",
176            ProgramType::LwtOut => "lwt_out",
177            ProgramType::LwtXmit => "lwt_xmit",
178            ProgramType::SockOps => "sock_ops",
179            ProgramType::SkSkb => "sk_skb",
180            ProgramType::CgroupDevice => "cgroup_device",
181            ProgramType::SkMsg => "sk_msg",
182            ProgramType::RawTracepoint => "raw_tracepoint",
183            ProgramType::CgroupSockAddr => "cgroup_sock_addr",
184            ProgramType::LwtSeg6Local => "lwt_seg6local",
185            ProgramType::LircMode2 => "lirc_mode2",
186            ProgramType::SkReuseport => "sk_reuseport",
187            ProgramType::FlowDissector => "flow_dissector",
188            ProgramType::CgroupSysctl => "cgroup_sysctl",
189            ProgramType::RawTracepointWritable => "raw_tracepoint_writable",
190            ProgramType::CgroupSockopt => "cgroup_sockopt",
191            ProgramType::Tracing => "tracing",
192            ProgramType::StructOps => "struct_ops",
193            ProgramType::Ext => "ext",
194            ProgramType::Lsm => "lsm",
195            ProgramType::SkLookup => "sk_lookup",
196            ProgramType::Syscall => "syscall",
197        };
198        write!(f, "{v}")
199    }
200}
201
202#[derive(Copy, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
203pub enum ProbeType {
204    Kprobe,
205    Kretprobe,
206    Uprobe,
207    Uretprobe,
208}
209
210impl TryFrom<i32> for ProbeType {
211    type Error = ParseError;
212
213    fn try_from(value: i32) -> Result<Self, Self::Error> {
214        Ok(match value {
215            0 => ProbeType::Kprobe,
216            1 => ProbeType::Kretprobe,
217            2 => ProbeType::Uprobe,
218            3 => ProbeType::Uretprobe,
219            other => {
220                return Err(ParseError::InvalidProbeType {
221                    probe: other.to_string(),
222                })
223            }
224        })
225    }
226}
227
228impl From<aya::programs::ProbeKind> for ProbeType {
229    fn from(value: aya::programs::ProbeKind) -> Self {
230        match value {
231            aya::programs::ProbeKind::KProbe => ProbeType::Kprobe,
232            aya::programs::ProbeKind::KRetProbe => ProbeType::Kretprobe,
233            aya::programs::ProbeKind::UProbe => ProbeType::Uprobe,
234            aya::programs::ProbeKind::URetProbe => ProbeType::Uretprobe,
235        }
236    }
237}
238
239impl std::fmt::Display for ProbeType {
240    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241        let v = match self {
242            ProbeType::Kprobe => "kprobe",
243            ProbeType::Kretprobe => "kretprobe",
244            ProbeType::Uprobe => "uprobe",
245            ProbeType::Uretprobe => "uretprobe",
246        };
247        write!(f, "{v}")
248    }
249}
250
251#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
252pub enum XdpProceedOnEntry {
253    Aborted,
254    Drop,
255    Pass,
256    Tx,
257    Redirect,
258    DispatcherReturn = 31,
259}
260
261impl TryFrom<String> for XdpProceedOnEntry {
262    type Error = ParseError;
263    fn try_from(value: String) -> Result<Self, Self::Error> {
264        Ok(match value.as_str() {
265            "aborted" => XdpProceedOnEntry::Aborted,
266            "drop" => XdpProceedOnEntry::Drop,
267            "pass" => XdpProceedOnEntry::Pass,
268            "tx" => XdpProceedOnEntry::Tx,
269            "redirect" => XdpProceedOnEntry::Redirect,
270            "dispatcher_return" => XdpProceedOnEntry::DispatcherReturn,
271            proceedon => {
272                return Err(ParseError::InvalidProceedOn {
273                    proceedon: proceedon.to_string(),
274                })
275            }
276        })
277    }
278}
279
280impl TryFrom<i32> for XdpProceedOnEntry {
281    type Error = ParseError;
282    fn try_from(value: i32) -> Result<Self, Self::Error> {
283        Ok(match value {
284            0 => XdpProceedOnEntry::Aborted,
285            1 => XdpProceedOnEntry::Drop,
286            2 => XdpProceedOnEntry::Pass,
287            3 => XdpProceedOnEntry::Tx,
288            4 => XdpProceedOnEntry::Redirect,
289            31 => XdpProceedOnEntry::DispatcherReturn,
290            proceedon => {
291                return Err(ParseError::InvalidProceedOn {
292                    proceedon: proceedon.to_string(),
293                })
294            }
295        })
296    }
297}
298
299impl std::fmt::Display for XdpProceedOnEntry {
300    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301        let v = match self {
302            XdpProceedOnEntry::Aborted => "aborted",
303            XdpProceedOnEntry::Drop => "drop",
304            XdpProceedOnEntry::Pass => "pass",
305            XdpProceedOnEntry::Tx => "tx",
306            XdpProceedOnEntry::Redirect => "redirect",
307            XdpProceedOnEntry::DispatcherReturn => "dispatcher_return",
308        };
309        write!(f, "{v}")
310    }
311}
312
313#[derive(Serialize, Deserialize, Clone, Debug)]
314pub struct XdpProceedOn(Vec<XdpProceedOnEntry>);
315impl Default for XdpProceedOn {
316    fn default() -> Self {
317        XdpProceedOn(vec![
318            XdpProceedOnEntry::Pass,
319            XdpProceedOnEntry::DispatcherReturn,
320        ])
321    }
322}
323
324impl XdpProceedOn {
325    pub fn from_strings<T: AsRef<[String]>>(values: T) -> Result<XdpProceedOn, ParseError> {
326        let entries = values.as_ref();
327        let mut res = vec![];
328        for e in entries {
329            res.push(e.to_owned().try_into()?)
330        }
331        Ok(XdpProceedOn(res))
332    }
333
334    pub fn from_int32s<T: AsRef<[i32]>>(values: T) -> Result<XdpProceedOn, ParseError> {
335        let entries = values.as_ref();
336        if entries.is_empty() {
337            return Ok(XdpProceedOn::default());
338        }
339        let mut res = vec![];
340        for e in entries {
341            res.push((*e).try_into()?)
342        }
343        Ok(XdpProceedOn(res))
344    }
345
346    pub fn mask(&self) -> u32 {
347        let mut proceed_on_mask: u32 = 0;
348        for action in self.0.clone().into_iter() {
349            proceed_on_mask |= 1 << action as u32;
350        }
351        proceed_on_mask
352    }
353
354    pub fn as_action_vec(&self) -> Vec<i32> {
355        let mut res = vec![];
356        for entry in &self.0 {
357            res.push((*entry) as i32)
358        }
359        res
360    }
361}
362
363impl std::fmt::Display for XdpProceedOn {
364    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365        let res: Vec<String> = self.0.iter().map(|x| x.to_string()).collect();
366        write!(f, "{}", res.join(", "))
367    }
368}
369
370#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
371pub enum TcProceedOnEntry {
372    Unspec = -1,
373    Ok = 0,
374    Reclassify,
375    Shot,
376    Pipe,
377    Stolen,
378    Queued,
379    Repeat,
380    Redirect,
381    Trap,
382    DispatcherReturn = 30,
383}
384
385impl TryFrom<String> for TcProceedOnEntry {
386    type Error = ParseError;
387    fn try_from(value: String) -> Result<Self, Self::Error> {
388        Ok(match value.as_str() {
389            "unspec" => TcProceedOnEntry::Unspec,
390            "ok" => TcProceedOnEntry::Ok,
391            "reclassify" => TcProceedOnEntry::Reclassify,
392            "shot" => TcProceedOnEntry::Shot,
393            "pipe" => TcProceedOnEntry::Pipe,
394            "stolen" => TcProceedOnEntry::Stolen,
395            "queued" => TcProceedOnEntry::Queued,
396            "repeat" => TcProceedOnEntry::Repeat,
397            "redirect" => TcProceedOnEntry::Redirect,
398            "trap" => TcProceedOnEntry::Trap,
399            "dispatcher_return" => TcProceedOnEntry::DispatcherReturn,
400            proceedon => {
401                return Err(ParseError::InvalidProceedOn {
402                    proceedon: proceedon.to_string(),
403                })
404            }
405        })
406    }
407}
408
409impl TryFrom<i32> for TcProceedOnEntry {
410    type Error = ParseError;
411    fn try_from(value: i32) -> Result<Self, Self::Error> {
412        Ok(match value {
413            -1 => TcProceedOnEntry::Unspec,
414            0 => TcProceedOnEntry::Ok,
415            1 => TcProceedOnEntry::Reclassify,
416            2 => TcProceedOnEntry::Shot,
417            3 => TcProceedOnEntry::Pipe,
418            4 => TcProceedOnEntry::Stolen,
419            5 => TcProceedOnEntry::Queued,
420            6 => TcProceedOnEntry::Repeat,
421            7 => TcProceedOnEntry::Redirect,
422            8 => TcProceedOnEntry::Trap,
423            30 => TcProceedOnEntry::DispatcherReturn,
424            proceedon => {
425                return Err(ParseError::InvalidProceedOn {
426                    proceedon: proceedon.to_string(),
427                })
428            }
429        })
430    }
431}
432
433impl std::fmt::Display for TcProceedOnEntry {
434    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
435        let v = match self {
436            TcProceedOnEntry::Unspec => "unspec",
437            TcProceedOnEntry::Ok => "ok",
438            TcProceedOnEntry::Reclassify => "reclassify",
439            TcProceedOnEntry::Shot => "shot",
440            TcProceedOnEntry::Pipe => "pipe",
441            TcProceedOnEntry::Stolen => "stolen",
442            TcProceedOnEntry::Queued => "queued",
443            TcProceedOnEntry::Repeat => "repeat",
444            TcProceedOnEntry::Redirect => "redirect",
445            TcProceedOnEntry::Trap => "trap",
446            TcProceedOnEntry::DispatcherReturn => "dispatcher_return",
447        };
448        write!(f, "{v}")
449    }
450}
451
452#[derive(Serialize, Deserialize, Clone, Debug)]
453pub struct TcProceedOn(pub(crate) Vec<TcProceedOnEntry>);
454impl Default for TcProceedOn {
455    fn default() -> Self {
456        TcProceedOn(vec![
457            TcProceedOnEntry::Pipe,
458            TcProceedOnEntry::DispatcherReturn,
459        ])
460    }
461}
462
463impl TcProceedOn {
464    pub fn from_strings<T: AsRef<[String]>>(values: T) -> Result<TcProceedOn, ParseError> {
465        let entries = values.as_ref();
466        let mut res = vec![];
467        for e in entries {
468            res.push(e.to_owned().try_into()?)
469        }
470        Ok(TcProceedOn(res))
471    }
472
473    pub fn from_int32s<T: AsRef<[i32]>>(values: T) -> Result<TcProceedOn, ParseError> {
474        let entries = values.as_ref();
475        if entries.is_empty() {
476            return Ok(TcProceedOn::default());
477        }
478        let mut res = vec![];
479        for e in entries {
480            res.push((*e).try_into()?)
481        }
482        Ok(TcProceedOn(res))
483    }
484
485    // Valid TC return values range from -1 to 8.  Since -1 is not a valid shift value,
486    // 1 is added to the value to determine the bit to set in the bitmask and,
487    // correspondingly, The TC dispatcher adds 1 to the return value from the BPF program
488    // before it compares it to the configured bit mask.
489    pub fn mask(&self) -> u32 {
490        let mut proceed_on_mask: u32 = 0;
491        for action in self.0.clone().into_iter() {
492            proceed_on_mask |= 1 << ((action as i32) + 1);
493        }
494        proceed_on_mask
495    }
496
497    pub fn as_action_vec(&self) -> Vec<i32> {
498        let mut res = vec![];
499        for entry in &self.0 {
500            res.push((*entry) as i32)
501        }
502        res
503    }
504}
505
506impl std::fmt::Display for TcProceedOn {
507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
508        let res: Vec<String> = self.0.iter().map(|x| x.to_string()).collect();
509        write!(f, "{}", res.join(", "))
510    }
511}
512
513#[derive(Debug, Serialize, Deserialize, Clone)]
514pub enum ImagePullPolicy {
515    Always,
516    IfNotPresent,
517    Never,
518}
519
520impl std::fmt::Display for ImagePullPolicy {
521    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522        let v = match self {
523            ImagePullPolicy::Always => "Always",
524            ImagePullPolicy::IfNotPresent => "IfNotPresent",
525            ImagePullPolicy::Never => "Never",
526        };
527        write!(f, "{v}")
528    }
529}
530
531impl TryFrom<i32> for ImagePullPolicy {
532    type Error = ParseError;
533    fn try_from(value: i32) -> Result<Self, Self::Error> {
534        Ok(match value {
535            0 => ImagePullPolicy::Always,
536            1 => ImagePullPolicy::IfNotPresent,
537            2 => ImagePullPolicy::Never,
538            policy => {
539                return Err(ParseError::InvalidBytecodeImagePullPolicy {
540                    pull_policy: policy.to_string(),
541                })
542            }
543        })
544    }
545}
546
547impl TryFrom<&str> for ImagePullPolicy {
548    type Error = ParseError;
549    fn try_from(value: &str) -> Result<Self, Self::Error> {
550        Ok(match value {
551            "Always" => ImagePullPolicy::Always,
552            "IfNotPresent" => ImagePullPolicy::IfNotPresent,
553            "Never" => ImagePullPolicy::Never,
554            policy => {
555                return Err(ParseError::InvalidBytecodeImagePullPolicy {
556                    pull_policy: policy.to_string(),
557                })
558            }
559        })
560    }
561}
562
563impl From<ImagePullPolicy> for i32 {
564    fn from(value: ImagePullPolicy) -> Self {
565        match value {
566            ImagePullPolicy::Always => 0,
567            ImagePullPolicy::IfNotPresent => 1,
568            ImagePullPolicy::Never => 2,
569        }
570    }
571}
572
573impl ToString for Location {
574    fn to_string(&self) -> String {
575        match &self {
576            // Cast imagePullPolicy into it's concrete type so we can easily print.
577            Location::Image(i) => format!(
578                "image: {{ url: {}, pullpolicy: {} }}",
579                i.url,
580                TryInto::<ImagePullPolicy>::try_into(i.image_pull_policy).unwrap()
581            ),
582            Location::File(p) => format!("file: {{ path: {p} }}"),
583        }
584    }
585}