-
Notifications
You must be signed in to change notification settings - Fork 247
/
cgroup_sysctl.rs
154 lines (140 loc) · 4.8 KB
/
cgroup_sysctl.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Cgroup sysctl programs.
use std::{
hash::Hash,
os::unix::prelude::{AsRawFd, RawFd},
};
use crate::{
generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL},
programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData,
ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
};
/// A program used to watch for sysctl changes.
///
/// [`CgroupSysctl`] programs can be attached to a cgroup and will be called every
/// time a process inside that cgroup tries to read from or write to a sysctl knob in proc.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 5.2.
///
/// # Examples
///
/// ```no_run
/// # #[derive(Debug, thiserror::Error)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[])?;
/// use std::fs::File;
/// use std::convert::TryInto;
/// use aya::programs::CgroupSysctl;
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let program: &mut CgroupSysctl = bpf.program_mut("cgroup_sysctl").unwrap().try_into()?;
/// program.load()?;
/// program.attach(file)?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SYSCTL")]
pub struct CgroupSysctl {
pub(crate) data: ProgramData<CgroupSysctlLink>,
}
impl CgroupSysctl {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_CGROUP_SYSCTL, &mut self.data)
}
/// Attaches the program to the given cgroup.
///
/// The returned value can be used to detach, see [CgroupSysctl::detach].
pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSysctlLinkId, ProgramError> {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create".to_owned(),
io_error,
},
)? as RawFd;
self.data
.links
.insert(CgroupSysctlLink(CgroupSysctlLinkInner::Fd(FdLink::new(
link_fd,
))))
} else {
bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL).map_err(|(_, io_error)| {
ProgramError::SyscallError {
call: "bpf_prog_attach".to_owned(),
io_error,
}
})?;
self.data
.links
.insert(CgroupSysctlLink(CgroupSysctlLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL),
)))
}
}
/// Takes ownership of the link referenced by the provided link_id.
///
/// The link will be detached on `Drop` and the caller is now responsible
/// for managing its lifetime.
pub fn forget_link(
&mut self,
link_id: CgroupSysctlLinkId,
) -> Result<OwnedLink<CgroupSysctlLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
/// Detaches the program.
///
/// See [CgroupSysctl::attach].
pub fn detach(&mut self, link_id: CgroupSysctlLinkId) -> Result<(), ProgramError> {
self.data.links.remove(link_id)
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
enum CgroupSysctlLinkIdInner {
Fd(<FdLink as Link>::Id),
ProgAttach(<ProgAttachLink as Link>::Id),
}
#[derive(Debug)]
enum CgroupSysctlLinkInner {
Fd(FdLink),
ProgAttach(ProgAttachLink),
}
impl Link for CgroupSysctlLinkInner {
type Id = CgroupSysctlLinkIdInner;
fn id(&self) -> Self::Id {
match self {
CgroupSysctlLinkInner::Fd(fd) => CgroupSysctlLinkIdInner::Fd(fd.id()),
CgroupSysctlLinkInner::ProgAttach(p) => CgroupSysctlLinkIdInner::ProgAttach(p.id()),
}
}
fn detach(self) -> Result<(), ProgramError> {
match self {
CgroupSysctlLinkInner::Fd(fd) => fd.detach(),
CgroupSysctlLinkInner::ProgAttach(p) => p.detach(),
}
}
}
define_link_wrapper!(
/// The link used by [CgroupSysctl] programs.
CgroupSysctlLink,
/// The type returned by [CgroupSysctl::attach]. Can be passed to [CgroupSysctl::detach].
CgroupSysctlLinkId,
CgroupSysctlLinkInner,
CgroupSysctlLinkIdInner
);