1#[macro_use]
2extern crate log;
3
4use std::fs::File;
5use std::io::{BufRead, BufReader, Write};
6use std::path::{Path, PathBuf};
7
8pub mod blkio;
9pub mod cgroup;
10pub mod cpu;
11pub mod cpuacct;
12pub mod cpuset;
13pub mod devices;
14pub mod error;
15pub mod freezer;
16pub mod hierarchies;
17pub mod hugetlb;
18pub mod memory;
19pub mod net_cls;
20pub mod net_prio;
21pub mod perf_event;
22pub mod pid;
23pub mod rdma;
24pub mod cgroup_builder;
25
26use blkio::BlkIoController;
27use cpu::CpuController;
28use cpuacct::CpuAcctController;
29use cpuset::CpuSetController;
30use devices::DevicesController;
31use error::*;
32use freezer::FreezerController;
33use hugetlb::HugeTlbController;
34use memory::MemController;
35use net_cls::NetClsController;
36use net_prio::NetPrioController;
37use perf_event::PerfEventController;
38use pid::PidController;
39use rdma::RdmaController;
40
41pub use cgroup::Cgroup;
42
43#[derive(Debug)]
45pub enum Subsystem {
46 Pid(PidController),
48 Mem(MemController),
50 CpuSet(CpuSetController),
52 CpuAcct(CpuAcctController),
54 Cpu(CpuController),
56 Devices(DevicesController),
58 Freezer(FreezerController),
60 NetCls(NetClsController),
62 BlkIo(BlkIoController),
64 PerfEvent(PerfEventController),
66 NetPrio(NetPrioController),
68 HugeTlb(HugeTlbController),
70 Rdma(RdmaController),
72}
73
74#[doc(hidden)]
75#[derive(Eq, PartialEq, Debug)]
76pub enum Controllers {
77 Pids,
78 Mem,
79 CpuSet,
80 CpuAcct,
81 Cpu,
82 Devices,
83 Freezer,
84 NetCls,
85 BlkIo,
86 PerfEvent,
87 NetPrio,
88 HugeTlb,
89 Rdma,
90}
91
92impl Controllers {
93 pub fn to_string(&self) -> String {
94 match self {
95 Controllers::Pids => return "pids".to_string(),
96 Controllers::Mem => return "memory".to_string(),
97 Controllers::CpuSet => return "cpuset".to_string(),
98 Controllers::CpuAcct => return "cpuacct".to_string(),
99 Controllers::Cpu => return "cpu".to_string(),
100 Controllers::Devices => return "devices".to_string(),
101 Controllers::Freezer => return "freezer".to_string(),
102 Controllers::NetCls => return "net_cls".to_string(),
103 Controllers::BlkIo => return "blkio".to_string(),
104 Controllers::PerfEvent => return "perf_event".to_string(),
105 Controllers::NetPrio => return "net_prio".to_string(),
106 Controllers::HugeTlb => return "hugetlb".to_string(),
107 Controllers::Rdma => return "rdma".to_string(),
108 }
109 }
110}
111
112mod sealed {
113 use super::*;
114
115 pub trait ControllerInternal {
116 fn apply(&self, res: &Resources) -> Result<()>;
117
118 fn control_type(&self) -> Controllers;
120 fn get_path(&self) -> &PathBuf;
121 fn get_path_mut(&mut self) -> &mut PathBuf;
122 fn get_base(&self) -> &PathBuf;
123
124 fn verify_path(&self) -> Result<()> {
125 if self.get_path().starts_with(self.get_base()) {
126 Ok(())
127 } else {
128 Err(Error::new(ErrorKind::InvalidPath))
129 }
130 }
131
132 fn open_path(&self, p: &str, w: bool) -> Result<File> {
133 let mut path = self.get_path().clone();
134 path.push(p);
135
136 self.verify_path()?;
137
138 if w {
139 match File::create(&path) {
140 Err(e) => return Err(Error::with_cause(ErrorKind::WriteFailed, e)),
141 Ok(file) => return Ok(file),
142 }
143 } else {
144 match File::open(&path) {
145 Err(e) => return Err(Error::with_cause(ErrorKind::ReadFailed, e)),
146 Ok(file) => return Ok(file),
147 }
148 }
149 }
150
151 #[doc(hidden)]
152 fn path_exists(&self, p: &str) -> bool {
153 if let Err(_) = self.verify_path() {
154 return false;
155 }
156
157 std::path::Path::new(p).exists()
158 }
159
160 }
161}
162
163pub(crate) use sealed::ControllerInternal;
164
165pub trait Controller {
169 #[doc(hidden)]
170 fn control_type(&self) -> Controllers;
171
172 fn path(&self) -> &Path;
174
175 fn apply(&self, res: &Resources) -> Result<()>;
178
179 fn create(&self);
181
182 fn exists(&self) -> bool;
184
185 fn delete(&self);
187
188 fn add_task(&self, pid: &CgroupPid) -> Result<()>;
190
191 fn tasks(&self) -> Vec<CgroupPid>;
193}
194
195impl<T> Controller for T where T: ControllerInternal {
196 fn control_type(&self) -> Controllers {
197 ControllerInternal::control_type(self)
198 }
199
200 fn path(&self) -> &Path {
201 self.get_path()
202 }
203
204 fn apply(&self, res: &Resources) -> Result<()> {
207 ControllerInternal::apply(self, res)
208 }
209
210 fn create(&self) {
212 self.verify_path().expect("path should be valid");
213
214 match ::std::fs::create_dir(self.get_path()) {
215 Ok(_) => (),
216 Err(e) => warn!("error create_dir {:?}", e),
217 }
218 }
219
220 fn exists(&self) -> bool {
222 self.get_path().exists()
223 }
224
225 fn delete(&self) {
227 if self.get_path().exists() {
228 let _ = ::std::fs::remove_dir(self.get_path());
229 }
230 }
231
232 fn add_task(&self, pid: &CgroupPid) -> Result<()> {
234 self.open_path("tasks", true).and_then(|mut file| {
235 file.write_all(pid.pid.to_string().as_ref())
236 .map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e))
237 })
238 }
239
240 fn tasks(&self) -> Vec<CgroupPid> {
242 self.open_path("tasks", false)
243 .and_then(|file| {
244 let bf = BufReader::new(file);
245 let mut v = Vec::new();
246 for line in bf.lines() {
247 if let Ok(line) = line {
248 let n = line.trim().parse().unwrap_or(0u64);
249 v.push(n);
250 }
251 }
252 Ok(v.into_iter().map(CgroupPid::from).collect())
253 }).unwrap_or(vec![])
254 }
255}
256
257#[doc(hidden)]
258pub trait ControllIdentifier {
259 fn controller_type() -> Controllers;
260}
261
262pub trait Hierarchy {
265 fn subsystems(&self) -> Vec<Subsystem>;
267
268 fn root(&self) -> PathBuf;
270
271 fn root_control_group(&self) -> Cgroup;
273
274 #[doc(hidden)]
278 fn check_support(&self, sub: Controllers) -> bool;
279}
280
281#[derive(Debug, Clone, Eq, PartialEq, Default)]
283pub struct MemoryResources {
284 pub update_values: bool,
286 pub kernel_memory_limit: u64,
288 pub memory_hard_limit: u64,
290 pub memory_soft_limit: u64,
293 pub kernel_tcp_memory_limit: u64,
295 pub memory_swap_limit: u64,
297 pub swappiness: u64,
303}
304
305#[derive(Debug, Clone, Eq, PartialEq, Default)]
307pub struct PidResources {
308 pub update_values: bool,
310 pub maximum_number_of_processes: pid::PidMax,
316}
317
318#[derive(Debug, Clone, Eq, PartialEq, Default)]
320pub struct CpuResources {
321 pub update_values: bool,
323 pub cpus: String,
327 pub mems: String,
330 pub shares: u64,
334 pub quota: i64,
336 pub period: u64,
338 pub realtime_runtime: i64,
340 pub realtime_period: u64,
342}
343
344#[derive(Debug, Clone, Eq, PartialEq, Default)]
346pub struct DeviceResource {
347 pub allow: bool,
349 pub devtype: ::devices::DeviceType,
351 pub major: i64,
353 pub minor: i64,
355 pub access: Vec<::devices::DevicePermissions>,
357}
358
359#[derive(Debug, Clone, Eq, PartialEq, Default)]
361pub struct DeviceResources {
362 pub update_values: bool,
364 pub devices: Vec<DeviceResource>,
366}
367
368#[derive(Debug, Clone, Eq, PartialEq, Default)]
370pub struct NetworkPriority {
371 pub name: String,
373 pub priority: u64,
375}
376
377#[derive(Debug, Clone, Eq, PartialEq, Default)]
380pub struct NetworkResources {
381 pub update_values: bool,
383 pub class_id: u64,
387 pub priorities: Vec<NetworkPriority>,
389}
390
391#[derive(Debug, Clone, Eq, PartialEq, Default)]
393pub struct HugePageResource {
394 pub size: String,
396 pub limit: u64,
399}
400
401#[derive(Debug, Clone, Eq, PartialEq, Default)]
403pub struct HugePageResources {
404 pub update_values: bool,
406 pub limits: Vec<HugePageResource>,
408}
409
410#[derive(Debug, Clone, Eq, PartialEq, Default)]
412pub struct BlkIoDeviceResource {
413 pub major: u64,
415 pub minor: u64,
417 pub weight: u16,
419 pub leaf_weight: u16,
421}
422
423#[derive(Debug, Clone, Eq, PartialEq, Default)]
425pub struct BlkIoDeviceThrottleResource {
426 pub major: u64,
428 pub minor: u64,
430 pub rate: u64,
432}
433
434#[derive(Debug, Clone, Eq, PartialEq, Default)]
436pub struct BlkIoResources {
437 pub update_values: bool,
439 pub weight: u16,
441 pub leaf_weight: u16,
443 pub weight_device: Vec<BlkIoDeviceResource>,
445 pub throttle_read_bps_device: Vec<BlkIoDeviceThrottleResource>,
447 pub throttle_read_iops_device: Vec<BlkIoDeviceThrottleResource>,
449 pub throttle_write_bps_device: Vec<BlkIoDeviceThrottleResource>,
451 pub throttle_write_iops_device: Vec<BlkIoDeviceThrottleResource>,
453}
454
455#[derive(Debug, Clone, Eq, PartialEq, Default)]
457pub struct Resources {
458 pub memory: MemoryResources,
460 pub pid: PidResources,
462 pub cpu: CpuResources,
464 pub devices: DeviceResources,
466 pub network: NetworkResources,
468 pub hugepages: HugePageResources,
470 pub blkio: BlkIoResources,
472}
473
474#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
477pub struct CgroupPid {
478 pub pid: u64,
480}
481
482impl From<u64> for CgroupPid {
483 fn from(u: u64) -> CgroupPid {
484 CgroupPid { pid: u }
485 }
486}
487
488impl<'a> From<&'a std::process::Child> for CgroupPid {
489 fn from(u: &std::process::Child) -> CgroupPid {
490 CgroupPid { pid: u.id() as u64 }
491 }
492}
493
494impl Subsystem {
495 fn enter(self, path: &Path) -> Self {
496 match self {
497 Subsystem::Pid(cont) => Subsystem::Pid({
498 let mut c = cont.clone();
499 c.get_path_mut().push(path);
500 c
501 }),
502 Subsystem::Mem(cont) => Subsystem::Mem({
503 let mut c = cont.clone();
504 c.get_path_mut().push(path);
505 c
506 }),
507 Subsystem::CpuSet(cont) => Subsystem::CpuSet({
508 let mut c = cont.clone();
509 c.get_path_mut().push(path);
510 c
511 }),
512 Subsystem::CpuAcct(cont) => Subsystem::CpuAcct({
513 let mut c = cont.clone();
514 c.get_path_mut().push(path);
515 c
516 }),
517 Subsystem::Cpu(cont) => Subsystem::Cpu({
518 let mut c = cont.clone();
519 c.get_path_mut().push(path);
520 c
521 }),
522 Subsystem::Devices(cont) => Subsystem::Devices({
523 let mut c = cont.clone();
524 c.get_path_mut().push(path);
525 c
526 }),
527 Subsystem::Freezer(cont) => Subsystem::Freezer({
528 let mut c = cont.clone();
529 c.get_path_mut().push(path);
530 c
531 }),
532 Subsystem::NetCls(cont) => Subsystem::NetCls({
533 let mut c = cont.clone();
534 c.get_path_mut().push(path);
535 c
536 }),
537 Subsystem::BlkIo(cont) => Subsystem::BlkIo({
538 let mut c = cont.clone();
539 c.get_path_mut().push(path);
540 c
541 }),
542 Subsystem::PerfEvent(cont) => Subsystem::PerfEvent({
543 let mut c = cont.clone();
544 c.get_path_mut().push(path);
545 c
546 }),
547 Subsystem::NetPrio(cont) => Subsystem::NetPrio({
548 let mut c = cont.clone();
549 c.get_path_mut().push(path);
550 c
551 }),
552 Subsystem::HugeTlb(cont) => Subsystem::HugeTlb({
553 let mut c = cont.clone();
554 c.get_path_mut().push(path);
555 c
556 }),
557 Subsystem::Rdma(cont) => Subsystem::Rdma({
558 let mut c = cont.clone();
559 c.get_path_mut().push(path);
560 c
561 }),
562 }
563 }
564
565 fn to_controller(&self) -> &dyn Controller {
566 match self {
567 Subsystem::Pid(cont) => cont,
568 Subsystem::Mem(cont) => cont,
569 Subsystem::CpuSet(cont) => cont,
570 Subsystem::CpuAcct(cont) => cont,
571 Subsystem::Cpu(cont) => cont,
572 Subsystem::Devices(cont) => cont,
573 Subsystem::Freezer(cont) => cont,
574 Subsystem::NetCls(cont) => cont,
575 Subsystem::BlkIo(cont) => cont,
576 Subsystem::PerfEvent(cont) => cont,
577 Subsystem::NetPrio(cont) => cont,
578 Subsystem::HugeTlb(cont) => cont,
579 Subsystem::Rdma(cont) => cont,
580 }
581 }
582}