cgroups/
lib.rs

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/// Contains all the subsystems that are available in this crate.
44#[derive(Debug)]
45pub enum Subsystem {
46    /// Controller for the `Pid` subsystem, see `PidController` for more information.
47    Pid(PidController),
48    /// Controller for the `Mem` subsystem, see `MemController` for more information.
49    Mem(MemController),
50    /// Controller for the `CpuSet subsystem, see `CpuSetController` for more information.
51    CpuSet(CpuSetController),
52    /// Controller for the `CpuAcct` subsystem, see `CpuAcctController` for more information.
53    CpuAcct(CpuAcctController),
54    /// Controller for the `Cpu` subsystem, see `CpuController` for more information.
55    Cpu(CpuController),
56    /// Controller for the `Devices` subsystem, see `DevicesController` for more information.
57    Devices(DevicesController),
58    /// Controller for the `Freezer` subsystem, see `FreezerController` for more information.
59    Freezer(FreezerController),
60    /// Controller for the `NetCls` subsystem, see `NetClsController` for more information.
61    NetCls(NetClsController),
62    /// Controller for the `BlkIo` subsystem, see `BlkIoController` for more information.
63    BlkIo(BlkIoController),
64    /// Controller for the `PerfEvent` subsystem, see `PerfEventController` for more information.
65    PerfEvent(PerfEventController),
66    /// Controller for the `NetPrio` subsystem, see `NetPrioController` for more information.
67    NetPrio(NetPrioController),
68    /// Controller for the `HugeTlb` subsystem, see `HugeTlbController` for more information.
69    HugeTlb(HugeTlbController),
70    /// Controller for the `Rdma` subsystem, see `RdmaController` for more information.
71    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        // meta stuff
119        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
165/// A Controller is a subsystem attached to the control group.
166///
167/// Implementors are able to control certain aspects of a control group.
168pub trait Controller {
169    #[doc(hidden)]
170    fn control_type(&self) -> Controllers;
171
172    /// The file system path to the controller.
173    fn path(&self) -> &Path;
174
175    /// Apply a set of resources to the Controller, invoking its internal functions to pass the
176    /// kernel the information.
177    fn apply(&self, res: &Resources) -> Result<()>;
178
179    /// Create this controller
180    fn create(&self);
181
182    /// Does this controller already exist?
183    fn exists(&self) -> bool;
184
185    /// Delete the controller.
186    fn delete(&self);
187
188    /// Attach a task to this controller.
189    fn add_task(&self, pid: &CgroupPid) -> Result<()>;
190
191    /// Get the list of tasks that this controller has.
192    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    /// Apply a set of resources to the Controller, invoking its internal functions to pass the
205    /// kernel the information.
206    fn apply(&self, res: &Resources) -> Result<()> {
207        ControllerInternal::apply(self, res)
208    }
209
210    /// Create this controller
211    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    /// Does this controller already exist?
221    fn exists(&self) -> bool {
222        self.get_path().exists()
223    }
224
225    /// Delete the controller.
226    fn delete(&self) {
227        if self.get_path().exists() {
228            let _ = ::std::fs::remove_dir(self.get_path());
229        }
230    }
231
232    /// Attach a task to this controller.
233    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    /// Get the list of tasks that this controller has.
241    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
262/// Control group hierarchy (right now, only V1 is supported, but in the future Unified will be
263/// implemented as well).
264pub trait Hierarchy {
265    /// Returns what subsystems are supported by the hierarchy.
266    fn subsystems(&self) -> Vec<Subsystem>;
267
268    /// Returns the root directory of the hierarchy.
269    fn root(&self) -> PathBuf;
270
271    /// Return a handle to the root control group in the hierarchy.
272    fn root_control_group(&self) -> Cgroup;
273
274    /// Checks whether a certain subsystem is supported in the hierarchy.
275    ///
276    /// This is an internal function and should not be used.
277    #[doc(hidden)]
278    fn check_support(&self, sub: Controllers) -> bool;
279}
280
281/// Resource limits for the memory subsystem.
282#[derive(Debug, Clone, Eq, PartialEq, Default)]
283pub struct MemoryResources {
284    /// Whether values should be applied to the controller.
285    pub update_values: bool,
286    /// How much memory (in bytes) can the kernel consume.
287    pub kernel_memory_limit: u64,
288    /// Upper limit of memory usage of the control group's tasks.
289    pub memory_hard_limit: u64,
290    /// How much memory the tasks in the control group can use when the system is under memory
291    /// pressure.
292    pub memory_soft_limit: u64,
293    /// How much of the kernel's memory (in bytes) can be used for TCP-related buffers.
294    pub kernel_tcp_memory_limit: u64,
295    /// How much memory and swap together can the tasks in the control group use.
296    pub memory_swap_limit: u64,
297    /// Controls the tendency of the kernel to swap out parts of the address space of the tasks to
298    /// disk. Lower value implies less likely.
299    ///
300    /// Note, however, that a value of zero does not mean the process is never swapped out. Use the
301    /// traditional `mlock(2)` system call for that purpose.
302    pub swappiness: u64,
303}
304
305/// Resources limits on the number of processes.
306#[derive(Debug, Clone, Eq, PartialEq, Default)]
307pub struct PidResources {
308    /// Whether values should be applied to the controller.
309    pub update_values: bool,
310    /// The maximum number of processes that can exist in the control group.
311    ///
312    /// Note that attaching processes to the control group will still succeed _even_ if the limit
313    /// would be violated, however forks/clones inside the control group will have with `EAGAIN` if
314    /// they would violate the limit set here.
315    pub maximum_number_of_processes: pid::PidMax,
316}
317
318/// Resources limits about how the tasks can use the CPU.
319#[derive(Debug, Clone, Eq, PartialEq, Default)]
320pub struct CpuResources {
321    /// Whether values should be applied to the controller.
322    pub update_values: bool,
323    // cpuset
324    /// A comma-separated list of CPU IDs where the task in the control group can run. Dashes
325    /// between numbers indicate ranges.
326    pub cpus: String,
327    /// Same syntax as the `cpus` field of this structure, but applies to memory nodes instead of
328    /// processors.
329    pub mems: String,
330    // cpu
331    /// Weight of how much of the total CPU time should this control group get. Note that this is
332    /// hierarchical, so this is weighted against the siblings of this control group.
333    pub shares: u64,
334    /// In one `period`, how much can the tasks run in nanoseconds.
335    pub quota: i64,
336    /// Period of time in nanoseconds.
337    pub period: u64,
338    /// This is currently a no-operation.
339    pub realtime_runtime: i64,
340    /// This is currently a no-operation.
341    pub realtime_period: u64,
342}
343
344/// A device resource that can be allowed or denied access to.
345#[derive(Debug, Clone, Eq, PartialEq, Default)]
346pub struct DeviceResource {
347    /// If true, access to the device is allowed, otherwise it's denied.
348    pub allow: bool,
349    /// `'c'` for character device, `'b'` for block device; or `'a'` for all devices.
350    pub devtype: ::devices::DeviceType,
351    /// The major number of the device.
352    pub major: i64,
353    /// The minor number of the device.
354    pub minor: i64,
355    /// Sequence of `'r'`, `'w'` or `'m'`, each denoting read, write or mknod permissions.
356    pub access: Vec<::devices::DevicePermissions>,
357}
358
359/// Limit the usage of devices for the control group's tasks.
360#[derive(Debug, Clone, Eq, PartialEq, Default)]
361pub struct DeviceResources {
362    /// Whether values should be applied to the controller.
363    pub update_values: bool,
364    /// For each device in the list, the limits in the structure are applied.
365    pub devices: Vec<DeviceResource>,
366}
367
368/// Assigned priority for a network device.
369#[derive(Debug, Clone, Eq, PartialEq, Default)]
370pub struct NetworkPriority {
371    /// The name (as visible in `ifconfig`) of the interface.
372    pub name: String,
373    /// Assigned priority.
374    pub priority: u64,
375}
376
377/// Collections of limits and tags that can be imposed on packets emitted by the tasks in the
378/// control group.
379#[derive(Debug, Clone, Eq, PartialEq, Default)]
380pub struct NetworkResources {
381    /// Whether values should be applied to the controller.
382    pub update_values: bool,
383    /// The networking class identifier to attach to the packets.
384    ///
385    /// This can then later be used in iptables and such to have special rules.
386    pub class_id: u64,
387    /// Priority of the egress traffic for each interface.
388    pub priorities: Vec<NetworkPriority>,
389}
390
391/// A hugepage type and its consumption limit for the control group.
392#[derive(Debug, Clone, Eq, PartialEq, Default)]
393pub struct HugePageResource {
394    /// The size of the hugepage, i.e. `2MB`, `1GB`, etc.
395    pub size: String,
396    /// The amount of bytes (of memory consumed by the tasks) that are allowed to be backed by
397    /// hugepages.
398    pub limit: u64,
399}
400
401/// Provides the ability to set consumption limit on each type of hugepages.
402#[derive(Debug, Clone, Eq, PartialEq, Default)]
403pub struct HugePageResources {
404    /// Whether values should be applied to the controller.
405    pub update_values: bool,
406    /// Set a limit of consumption for each hugepages type.
407    pub limits: Vec<HugePageResource>,
408}
409
410/// Weight for a particular block device.
411#[derive(Debug, Clone, Eq, PartialEq, Default)]
412pub struct BlkIoDeviceResource {
413    /// The major number of the device.
414    pub major: u64,
415    /// The minor number of the device.
416    pub minor: u64,
417    /// The weight of the device against the descendant nodes.
418    pub weight: u16,
419    /// The weight of the device against the sibling nodes.
420    pub leaf_weight: u16,
421}
422
423/// Provides the ability to throttle a device (both byte/sec, and IO op/s)
424#[derive(Debug, Clone, Eq, PartialEq, Default)]
425pub struct BlkIoDeviceThrottleResource {
426    /// The major number of the device.
427    pub major: u64,
428    /// The minor number of the device.
429    pub minor: u64,
430    /// The rate.
431    pub rate: u64,
432}
433
434/// General block I/O resource limits.
435#[derive(Debug, Clone, Eq, PartialEq, Default)]
436pub struct BlkIoResources {
437    /// Whether values should be applied to the controller.
438    pub update_values: bool,
439    /// The weight of the control group against descendant nodes.
440    pub weight: u16,
441    /// The weight of the control group against sibling nodes.
442    pub leaf_weight: u16,
443    /// For each device, a separate weight (both normal and leaf) can be provided.
444    pub weight_device: Vec<BlkIoDeviceResource>,
445    /// Throttled read bytes/second can be provided for each device.
446    pub throttle_read_bps_device: Vec<BlkIoDeviceThrottleResource>,
447    /// Throttled read IO operations per second can be provided for each device.
448    pub throttle_read_iops_device: Vec<BlkIoDeviceThrottleResource>,
449    /// Throttled written bytes/second can be provided for each device.
450    pub throttle_write_bps_device: Vec<BlkIoDeviceThrottleResource>,
451    /// Throttled write IO operations per second can be provided for each device.
452    pub throttle_write_iops_device: Vec<BlkIoDeviceThrottleResource>,
453}
454
455/// The resource limits and constraints that will be set on the control group.
456#[derive(Debug, Clone, Eq, PartialEq, Default)]
457pub struct Resources {
458    /// Memory usage related limits.
459    pub memory: MemoryResources,
460    /// Process identifier related limits.
461    pub pid: PidResources,
462    /// CPU related limits.
463    pub cpu: CpuResources,
464    /// Device related limits.
465    pub devices: DeviceResources,
466    /// Network related tags and limits.
467    pub network: NetworkResources,
468    /// Hugepages consumption related limits.
469    pub hugepages: HugePageResources,
470    /// Block device I/O related limits.
471    pub blkio: BlkIoResources,
472}
473
474/// A structure representing a `pid`. Currently implementations exist for `u64` and
475/// `std::process::Child`.
476#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
477pub struct CgroupPid {
478    /// The process identifier
479    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}