Skip to main content

oci_spec/runtime/
linux.rs

1use crate::error::{oci_error, OciSpecError};
2
3use derive_builder::Builder;
4use getset::{CopyGetters, Getters, MutGetters, Setters};
5use serde::{Deserialize, Serialize};
6use std::{collections::HashMap, fmt::Display, path::PathBuf, vec};
7use strum_macros::{Display as StrumDisplay, EnumString};
8
9#[derive(
10    Builder, Clone, Debug, Deserialize, Eq, Getters, MutGetters, Setters, PartialEq, Serialize,
11)]
12#[serde(rename_all = "camelCase")]
13#[builder(
14    default,
15    pattern = "owned",
16    setter(into, strip_option),
17    build_fn(error = "OciSpecError")
18)]
19#[getset(get_mut = "pub", get = "pub", set = "pub")]
20/// Linux contains platform-specific configuration for Linux based
21/// containers.
22pub struct Linux {
23    #[serde(default, skip_serializing_if = "Option::is_none")]
24    /// NetDevices are key-value pairs, keyed by network device name on the host, moved to the container's network namespace.
25    net_devices: Option<HashMap<String, LinuxNetDevice>>,
26
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    /// UIDMappings specifies user mappings for supporting user namespaces.
29    uid_mappings: Option<Vec<LinuxIdMapping>>,
30
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    /// GIDMappings specifies group mappings for supporting user namespaces.
33    gid_mappings: Option<Vec<LinuxIdMapping>>,
34
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    /// Sysctl are a set of key value pairs that are set for the container
37    /// on start.
38    sysctl: Option<HashMap<String, String>>,
39
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    /// Resources contain cgroup information for handling resource
42    /// constraints for the container.
43    resources: Option<LinuxResources>,
44
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    /// CgroupsPath specifies the path to cgroups that are created and/or
47    /// joined by the container. The path is expected to be relative
48    /// to the cgroups mountpoint. If resources are specified,
49    /// the cgroups at CgroupsPath will be updated based on resources.
50    cgroups_path: Option<PathBuf>,
51
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    /// Namespaces contains the namespaces that are created and/or joined by
54    /// the container.
55    namespaces: Option<Vec<LinuxNamespace>>,
56
57    #[serde(default, skip_serializing_if = "Option::is_none")]
58    /// Devices are a list of device nodes that are created for the
59    /// container.
60    devices: Option<Vec<LinuxDevice>>,
61
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    /// Seccomp specifies the seccomp security settings for the container.
64    seccomp: Option<LinuxSeccomp>,
65
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    /// RootfsPropagation is the rootfs mount propagation mode for the
68    /// container.
69    rootfs_propagation: Option<String>,
70
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    /// MaskedPaths masks over the provided paths inside the container.
73    masked_paths: Option<Vec<String>>,
74
75    #[serde(default, skip_serializing_if = "Option::is_none")]
76    /// ReadonlyPaths sets the provided paths as RO inside the container.
77    readonly_paths: Option<Vec<String>>,
78
79    #[serde(default, skip_serializing_if = "Option::is_none")]
80    /// MountLabel specifies the selinux context for the mounts in the
81    /// container.
82    mount_label: Option<String>,
83
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    /// IntelRdt contains Intel Resource Director Technology (RDT)
86    /// information for handling resource constraints and monitoring metrics
87    /// (e.g., L3 cache, memory bandwidth) for the container.
88    intel_rdt: Option<LinuxIntelRdt>,
89
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    /// MemoryPolicy contains NUMA memory policy for the container.
92    memory_policy: Option<LinuxMemoryPolicy>,
93
94    #[serde(default, skip_serializing_if = "Option::is_none")]
95    /// Personality contains configuration for the Linux personality
96    /// syscall.
97    personality: Option<LinuxPersonality>,
98
99    #[serde(default, skip_serializing_if = "Option::is_none")]
100    /// TimeOffsets specifies the offset for supporting time namespaces.
101    time_offsets: Option<HashMap<String, LinuxTimeOffset>>,
102}
103
104// Default impl for Linux (see functions for more info)
105impl Default for Linux {
106    fn default() -> Self {
107        Linux {
108            // Creates empty Hashmap
109            net_devices: None,
110            // Creates empty Vec
111            uid_mappings: Default::default(),
112            // Creates empty Vec
113            gid_mappings: Default::default(),
114            // Empty sysctl Hashmap
115            sysctl: Default::default(),
116            resources: Some(LinuxResources {
117                devices: vec![].into(),
118                memory: Default::default(),
119                cpu: Default::default(),
120                pids: Default::default(),
121                block_io: Default::default(),
122                hugepage_limits: Default::default(),
123                network: Default::default(),
124                rdma: Default::default(),
125                unified: Default::default(),
126            }),
127            // Defaults to None
128            cgroups_path: Default::default(),
129            namespaces: get_default_namespaces().into(),
130            // Empty Vec
131            devices: Default::default(),
132            // Empty String
133            rootfs_propagation: Default::default(),
134            masked_paths: get_default_maskedpaths().into(),
135            readonly_paths: get_default_readonly_paths().into(),
136            // Empty String
137            mount_label: Default::default(),
138            seccomp: None,
139            intel_rdt: None,
140            memory_policy: None,
141            personality: None,
142            time_offsets: None,
143        }
144    }
145}
146
147impl Linux {
148    /// Return rootless Linux configuration.
149    pub fn rootless(uid: u32, gid: u32) -> Self {
150        let mut namespaces = get_default_namespaces();
151        namespaces.retain(|ns| ns.typ != LinuxNamespaceType::Network);
152        namespaces.push(LinuxNamespace {
153            typ: LinuxNamespaceType::User,
154            ..Default::default()
155        });
156        Self {
157            resources: None,
158            uid_mappings: Some(vec![LinuxIdMapping {
159                container_id: 0,
160                host_id: uid,
161                size: 1,
162            }]),
163            gid_mappings: Some(vec![LinuxIdMapping {
164                container_id: 0,
165                host_id: gid,
166                size: 1,
167            }]),
168            namespaces: Some(namespaces),
169            ..Default::default()
170        }
171    }
172}
173
174#[derive(
175    Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
176)]
177#[serde(rename_all = "camelCase")]
178#[builder(
179    default,
180    pattern = "owned",
181    setter(into, strip_option),
182    build_fn(error = "OciSpecError")
183)]
184#[getset(get_copy = "pub", set = "pub")]
185/// LinuxIDMapping specifies UID/GID mappings.
186pub struct LinuxIdMapping {
187    #[serde(default, rename = "hostID")]
188    /// HostID is the starting UID/GID on the host to be mapped to
189    /// `container_id`.
190    host_id: u32,
191
192    #[serde(default, rename = "containerID")]
193    /// ContainerID is the starting UID/GID in the container.
194    container_id: u32,
195
196    #[serde(default)]
197    /// Size is the number of IDs to be mapped.
198    size: u32,
199}
200
201#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, EnumString)]
202#[strum(serialize_all = "lowercase")]
203#[serde(rename_all = "lowercase")]
204/// Device types
205pub enum LinuxDeviceType {
206    /// All
207    A,
208
209    /// block (buffered)
210    B,
211
212    /// character (unbuffered)
213    C,
214
215    /// character (unbufferd)
216    U,
217
218    /// FIFO
219    P,
220}
221
222#[allow(clippy::derivable_impls)] // because making it clear that All is the default
223impl Default for LinuxDeviceType {
224    fn default() -> LinuxDeviceType {
225        LinuxDeviceType::A
226    }
227}
228
229impl LinuxDeviceType {
230    /// Retrieve a string reference for the device type.
231    pub fn as_str(&self) -> &str {
232        match self {
233            Self::A => "a",
234            Self::B => "b",
235            Self::C => "c",
236            Self::U => "u",
237            Self::P => "p",
238        }
239    }
240}
241
242#[derive(
243    Builder,
244    Clone,
245    Debug,
246    Default,
247    Deserialize,
248    Eq,
249    Getters,
250    MutGetters,
251    Setters,
252    PartialEq,
253    Serialize,
254)]
255#[builder(
256    default,
257    pattern = "owned",
258    setter(into, strip_option),
259    build_fn(error = "OciSpecError")
260)]
261/// LinuxNetDevice represents a single network device to be added to the container's network namespace
262pub struct LinuxNetDevice {
263    #[serde(default)]
264    #[getset(get_mut = "pub", get = "pub", set = "pub")]
265    /// Name of the device in the container namespace
266    name: Option<String>,
267}
268
269#[derive(
270    Builder,
271    Clone,
272    CopyGetters,
273    Debug,
274    Default,
275    Deserialize,
276    Eq,
277    Getters,
278    MutGetters,
279    Setters,
280    PartialEq,
281    Serialize,
282)]
283#[builder(
284    default,
285    pattern = "owned",
286    setter(into, strip_option),
287    build_fn(error = "OciSpecError")
288)]
289/// Represents a device rule for the devices specified to the device
290/// controller
291pub struct LinuxDeviceCgroup {
292    #[serde(default)]
293    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
294    /// Allow or deny
295    allow: bool,
296
297    #[serde(default, rename = "type", skip_serializing_if = "Option::is_none")]
298    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
299    /// Device type, block, char, etc.
300    typ: Option<LinuxDeviceType>,
301
302    #[serde(default, skip_serializing_if = "Option::is_none")]
303    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
304    /// Device's major number
305    major: Option<i64>,
306
307    #[serde(default, skip_serializing_if = "Option::is_none")]
308    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
309    /// Device's minor number
310    minor: Option<i64>,
311
312    /// Cgroup access permissions format, rwm.
313    #[serde(default)]
314    #[getset(get_mut = "pub", get = "pub", set = "pub")]
315    access: Option<String>,
316}
317
318/// This ToString trait is automatically implemented for any type which implements the Display trait.
319/// As such, ToString shouldn’t be implemented directly: Display should be implemented instead,
320/// and you get the ToString implementation for free.
321impl Display for LinuxDeviceCgroup {
322    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
323        let major = self
324            .major
325            .map(|mj| mj.to_string())
326            .unwrap_or_else(|| "*".to_string());
327        let minor = self
328            .minor
329            .map(|mi| mi.to_string())
330            .unwrap_or_else(|| "*".to_string());
331        let access = self.access.as_deref().unwrap_or("");
332        write!(
333            f,
334            "{} {}:{} {}",
335            &self.typ.unwrap_or_default().as_str(),
336            &major,
337            &minor,
338            &access
339        )
340    }
341}
342
343#[derive(
344    Builder,
345    Clone,
346    Copy,
347    CopyGetters,
348    Debug,
349    Default,
350    Deserialize,
351    Eq,
352    PartialEq,
353    Serialize,
354    Setters,
355)]
356#[serde(rename_all = "camelCase")]
357#[builder(
358    default,
359    pattern = "owned",
360    setter(into, strip_option),
361    build_fn(error = "OciSpecError")
362)]
363#[getset(get_copy = "pub", set = "pub")]
364/// LinuxMemory for Linux cgroup 'memory' resource management.
365pub struct LinuxMemory {
366    #[serde(skip_serializing_if = "Option::is_none")]
367    #[getset(get_copy = "pub", set = "pub")]
368    /// Memory limit (in bytes).
369    limit: Option<i64>,
370
371    #[serde(skip_serializing_if = "Option::is_none")]
372    #[getset(get_copy = "pub", set = "pub")]
373    /// Memory reservation or soft_limit (in bytes).
374    reservation: Option<i64>,
375
376    #[serde(skip_serializing_if = "Option::is_none")]
377    #[getset(get_copy = "pub", set = "pub")]
378    /// Total memory limit (memory + swap).
379    swap: Option<i64>,
380
381    #[serde(skip_serializing_if = "Option::is_none")]
382    #[getset(get_copy = "pub", set = "pub")]
383    /// Kernel memory limit (in bytes).
384    kernel: Option<i64>,
385
386    #[serde(skip_serializing_if = "Option::is_none", rename = "kernelTCP")]
387    #[getset(get_copy = "pub", set = "pub")]
388    /// Kernel memory limit for tcp (in bytes).
389    kernel_tcp: Option<i64>,
390
391    #[serde(skip_serializing_if = "Option::is_none")]
392    #[getset(get_copy = "pub", set = "pub")]
393    /// How aggressive the kernel will swap memory pages.
394    swappiness: Option<u64>,
395
396    #[serde(skip_serializing_if = "Option::is_none", rename = "disableOOMKiller")]
397    #[getset(get_copy = "pub", set = "pub")]
398    /// DisableOOMKiller disables the OOM killer for out of memory
399    /// conditions.
400    disable_oom_killer: Option<bool>,
401
402    #[serde(skip_serializing_if = "Option::is_none")]
403    #[getset(get_copy = "pub", set = "pub")]
404    /// Enables hierarchical memory accounting
405    use_hierarchy: Option<bool>,
406
407    #[serde(skip_serializing_if = "Option::is_none")]
408    #[getset(get_copy = "pub", set = "pub")]
409    /// Enables checking if a new memory limit is lower
410    check_before_update: Option<bool>,
411}
412
413#[derive(
414    Builder,
415    Clone,
416    CopyGetters,
417    Debug,
418    Default,
419    Deserialize,
420    Eq,
421    Getters,
422    Setters,
423    PartialEq,
424    Serialize,
425)]
426#[serde(rename_all = "camelCase")]
427#[builder(
428    default,
429    pattern = "owned",
430    setter(into, strip_option),
431    build_fn(error = "OciSpecError")
432)]
433/// LinuxCPU for Linux cgroup 'cpu' resource management.
434pub struct LinuxCpu {
435    #[serde(skip_serializing_if = "Option::is_none")]
436    #[getset(get_copy = "pub", set = "pub")]
437    /// CPU shares (relative weight (ratio) vs. other cgroups with cpu
438    /// shares).
439    shares: Option<u64>,
440
441    #[serde(skip_serializing_if = "Option::is_none")]
442    #[getset(get_copy = "pub", set = "pub")]
443    /// CPU hardcap limit (in usecs). Allowed cpu time in a given period.
444    quota: Option<i64>,
445
446    #[serde(skip_serializing_if = "Option::is_none")]
447    #[getset(get_copy = "pub", set = "pub")]
448    /// Cgroups are configured with minimum weight, 0: default behavior, 1: SCHED_IDLE.
449    idle: Option<i64>,
450
451    #[serde(skip_serializing_if = "Option::is_none")]
452    #[getset(get_copy = "pub", set = "pub")]
453    /// Maximum amount of accumulated time in microseconds for which tasks
454    /// in a cgroup can run additionally for burst during one period
455    burst: Option<u64>,
456
457    #[serde(skip_serializing_if = "Option::is_none")]
458    #[getset(get_copy = "pub", set = "pub")]
459    /// CPU period to be used for hardcapping (in usecs).
460    period: Option<u64>,
461
462    #[serde(skip_serializing_if = "Option::is_none")]
463    #[getset(get_copy = "pub", set = "pub")]
464    /// How much time realtime scheduling may use (in usecs).
465    realtime_runtime: Option<i64>,
466
467    #[serde(skip_serializing_if = "Option::is_none")]
468    #[getset(get_copy = "pub", set = "pub")]
469    /// CPU period to be used for realtime scheduling (in usecs).
470    realtime_period: Option<u64>,
471
472    #[serde(default, skip_serializing_if = "Option::is_none")]
473    #[getset(get = "pub", set = "pub")]
474    /// CPUs to use within the cpuset. Default is to use any CPU available.
475    cpus: Option<String>,
476
477    #[serde(default, skip_serializing_if = "Option::is_none")]
478    #[getset(get = "pub", set = "pub")]
479    /// List of memory nodes in the cpuset. Default is to use any available
480    /// memory node.
481    mems: Option<String>,
482}
483
484#[derive(
485    Builder,
486    Clone,
487    Copy,
488    Debug,
489    Default,
490    Deserialize,
491    Eq,
492    CopyGetters,
493    Setters,
494    PartialEq,
495    Serialize,
496)]
497#[builder(
498    default,
499    pattern = "owned",
500    setter(into, strip_option),
501    build_fn(error = "OciSpecError")
502)]
503#[getset(get_copy = "pub", set = "pub")]
504/// LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3).
505pub struct LinuxPids {
506    #[serde(default)]
507    /// Maximum number of PIDs. Default is "no limit".
508    limit: i64,
509}
510
511#[derive(
512    Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
513)]
514#[serde(rename_all = "camelCase")]
515#[builder(
516    default,
517    pattern = "owned",
518    setter(into, strip_option),
519    build_fn(error = "OciSpecError")
520)]
521#[getset(get_copy = "pub", set = "pub")]
522/// LinuxWeightDevice struct holds a `major:minor weight` pair for
523/// weightDevice.
524pub struct LinuxWeightDevice {
525    #[serde(default)]
526    /// Major is the device's major number.
527    major: i64,
528
529    #[serde(default)]
530    /// Minor is the device's minor number.
531    minor: i64,
532
533    #[serde(skip_serializing_if = "Option::is_none")]
534    /// Weight is the bandwidth rate for the device.
535    weight: Option<u16>,
536
537    #[serde(skip_serializing_if = "Option::is_none")]
538    /// LeafWeight is the bandwidth rate for the device while competing with
539    /// the cgroup's child cgroups, CFQ scheduler only.
540    leaf_weight: Option<u16>,
541}
542
543#[derive(
544    Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
545)]
546#[builder(
547    default,
548    pattern = "owned",
549    setter(into, strip_option),
550    build_fn(error = "OciSpecError")
551)]
552#[getset(get_copy = "pub", set = "pub")]
553/// LinuxThrottleDevice struct holds a `major:minor rate_per_second` pair.
554pub struct LinuxThrottleDevice {
555    #[serde(default)]
556    /// Major is the device's major number.
557    major: i64,
558
559    #[serde(default)]
560    /// Minor is the device's minor number.
561    minor: i64,
562
563    #[serde(default)]
564    /// Rate is the IO rate limit per cgroup per device.
565    rate: u64,
566}
567
568#[derive(
569    Builder,
570    Clone,
571    CopyGetters,
572    Debug,
573    Default,
574    Deserialize,
575    Eq,
576    Getters,
577    Setters,
578    PartialEq,
579    Serialize,
580)]
581#[serde(rename_all = "camelCase")]
582#[builder(
583    default,
584    pattern = "owned",
585    setter(into, strip_option),
586    build_fn(error = "OciSpecError")
587)]
588/// LinuxBlockIO for Linux cgroup 'blkio' resource management.
589pub struct LinuxBlockIo {
590    #[serde(skip_serializing_if = "Option::is_none")]
591    #[getset(get_copy = "pub", set = "pub")]
592    /// Specifies per cgroup weight.
593    weight: Option<u16>,
594
595    #[serde(skip_serializing_if = "Option::is_none")]
596    #[getset(get_copy = "pub", set = "pub")]
597    /// Specifies tasks' weight in the given cgroup while competing with the
598    /// cgroup's child cgroups, CFQ scheduler only.
599    leaf_weight: Option<u16>,
600
601    #[serde(skip_serializing_if = "Option::is_none")]
602    #[getset(get = "pub", set = "pub")]
603    /// Weight per cgroup per device, can override BlkioWeight.
604    weight_device: Option<Vec<LinuxWeightDevice>>,
605
606    #[serde(skip_serializing_if = "Option::is_none")]
607    #[getset(get = "pub", set = "pub")]
608    /// IO read rate limit per cgroup per device, bytes per second.
609    throttle_read_bps_device: Option<Vec<LinuxThrottleDevice>>,
610
611    #[serde(skip_serializing_if = "Option::is_none")]
612    #[getset(get = "pub", set = "pub")]
613    /// IO write rate limit per cgroup per device, bytes per second.
614    throttle_write_bps_device: Option<Vec<LinuxThrottleDevice>>,
615
616    #[serde(
617        skip_serializing_if = "Option::is_none",
618        rename = "throttleReadIOPSDevice"
619    )]
620    #[getset(get = "pub", set = "pub")]
621    /// IO read rate limit per cgroup per device, IO per second.
622    throttle_read_iops_device: Option<Vec<LinuxThrottleDevice>>,
623
624    #[serde(
625        skip_serializing_if = "Option::is_none",
626        rename = "throttleWriteIOPSDevice"
627    )]
628    #[getset(get = "pub", set = "pub")]
629    /// IO write rate limit per cgroup per device, IO per second.
630    throttle_write_iops_device: Option<Vec<LinuxThrottleDevice>>,
631}
632
633#[derive(
634    Builder,
635    Clone,
636    CopyGetters,
637    Debug,
638    Default,
639    Deserialize,
640    Eq,
641    Getters,
642    Setters,
643    PartialEq,
644    Serialize,
645)]
646#[serde(rename_all = "camelCase")]
647#[builder(
648    default,
649    pattern = "owned",
650    setter(into, strip_option),
651    build_fn(error = "OciSpecError")
652)]
653/// LinuxHugepageLimit structure corresponds to limiting kernel hugepages.
654/// Default to reservation limits if supported. Otherwise fallback to page fault limits.
655pub struct LinuxHugepageLimit {
656    #[serde(default)]
657    #[getset(get = "pub", set = "pub")]
658    /// Pagesize is the hugepage size.
659    /// Format: "&lt;size&gt;&lt;unit-prefix&gt;B' (e.g. 64KB, 2MB, 1GB, etc.)
660    page_size: String,
661
662    #[serde(default)]
663    #[getset(get_copy = "pub", set = "pub")]
664    /// Limit is the limit of "hugepagesize" hugetlb reservations (if supported) or usage.
665    limit: i64,
666}
667
668#[derive(
669    Builder,
670    Clone,
671    CopyGetters,
672    Debug,
673    Default,
674    Deserialize,
675    Eq,
676    Getters,
677    Setters,
678    PartialEq,
679    Serialize,
680)]
681#[builder(
682    default,
683    pattern = "owned",
684    setter(into, strip_option),
685    build_fn(error = "OciSpecError")
686)]
687/// LinuxInterfacePriority for network interfaces.
688pub struct LinuxInterfacePriority {
689    #[serde(default)]
690    #[getset(get = "pub", set = "pub")]
691    /// Name is the name of the network interface.
692    name: String,
693
694    #[serde(default)]
695    #[getset(get_copy = "pub", set = "pub")]
696    /// Priority for the interface.
697    priority: u32,
698}
699
700/// This ToString trait is automatically implemented for any type which implements the Display trait.
701/// As such, ToString shouldn’t be implemented directly: Display should be implemented instead,
702/// and you get the ToString implementation for free.
703impl Display for LinuxInterfacePriority {
704    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
705        // Serde serialization never fails since this is
706        // a combination of String and enums.
707        writeln!(f, "{} {}", self.name, self.priority)
708    }
709}
710
711#[derive(
712    Builder,
713    Clone,
714    CopyGetters,
715    Debug,
716    Default,
717    Deserialize,
718    Eq,
719    Getters,
720    Setters,
721    PartialEq,
722    Serialize,
723)]
724#[builder(
725    default,
726    pattern = "owned",
727    setter(into, strip_option),
728    build_fn(error = "OciSpecError")
729)]
730/// LinuxNetwork identification and priority configuration.
731pub struct LinuxNetwork {
732    #[serde(skip_serializing_if = "Option::is_none", rename = "classID")]
733    #[getset(get_copy = "pub", set = "pub")]
734    /// Set class identifier for container's network packets
735    class_id: Option<u32>,
736
737    #[serde(default, skip_serializing_if = "Option::is_none")]
738    #[getset(get = "pub", set = "pub")]
739    /// Set priority of network traffic for container.
740    priorities: Option<Vec<LinuxInterfacePriority>>,
741}
742
743#[derive(
744    Builder,
745    Clone,
746    CopyGetters,
747    Debug,
748    Default,
749    Deserialize,
750    Eq,
751    Getters,
752    MutGetters,
753    Setters,
754    PartialEq,
755    Serialize,
756)]
757#[serde(rename_all = "camelCase")]
758#[builder(
759    default,
760    pattern = "owned",
761    setter(into, strip_option),
762    build_fn(error = "OciSpecError")
763)]
764/// Resource constraints for container
765pub struct LinuxResources {
766    #[serde(default, skip_serializing_if = "Option::is_none")]
767    #[getset(get_mut = "pub", get = "pub", set = "pub")]
768    /// Devices configures the device allowlist.
769    devices: Option<Vec<LinuxDeviceCgroup>>,
770
771    #[serde(default, skip_serializing_if = "Option::is_none")]
772    #[getset(get_mut = "pub", get = "pub", set = "pub")]
773    /// Memory restriction configuration.
774    memory: Option<LinuxMemory>,
775
776    #[serde(default, skip_serializing_if = "Option::is_none")]
777    #[getset(get_mut = "pub", get = "pub", set = "pub")]
778    /// CPU resource restriction configuration.
779    cpu: Option<LinuxCpu>,
780
781    #[serde(default, skip_serializing_if = "Option::is_none")]
782    #[getset(get_mut = "pub", get = "pub", set = "pub")]
783    /// Task resource restrictions
784    pids: Option<LinuxPids>,
785
786    #[serde(default, skip_serializing_if = "Option::is_none", rename = "blockIO")]
787    #[getset(get_mut = "pub", get = "pub", set = "pub")]
788    /// BlockIO restriction configuration.
789    block_io: Option<LinuxBlockIo>,
790
791    #[serde(default, skip_serializing_if = "Option::is_none")]
792    #[getset(get_mut = "pub", get = "pub", set = "pub")]
793    /// Hugetlb limit (in bytes).
794    hugepage_limits: Option<Vec<LinuxHugepageLimit>>,
795
796    #[serde(default, skip_serializing_if = "Option::is_none")]
797    #[getset(get_mut = "pub", get = "pub", set = "pub")]
798    /// Network restriction configuration.
799    network: Option<LinuxNetwork>,
800
801    #[serde(default, skip_serializing_if = "Option::is_none")]
802    #[getset(get_mut = "pub", get = "pub", set = "pub")]
803    /// Rdma resource restriction configuration. Limits are a set of key
804    /// value pairs that define RDMA resource limits, where the key
805    /// is device name and value is resource limits.
806    rdma: Option<HashMap<String, LinuxRdma>>,
807
808    #[serde(default, skip_serializing_if = "Option::is_none")]
809    #[getset(get_mut = "pub", get = "pub", set = "pub")]
810    /// Unified resources.
811    unified: Option<HashMap<String, String>>,
812}
813
814#[derive(
815    Builder,
816    Clone,
817    Copy,
818    CopyGetters,
819    Debug,
820    Default,
821    Deserialize,
822    Eq,
823    MutGetters,
824    PartialEq,
825    Serialize,
826)]
827#[serde(rename_all = "camelCase")]
828#[builder(
829    default,
830    pattern = "owned",
831    setter(into, strip_option),
832    build_fn(error = "OciSpecError")
833)]
834#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
835/// LinuxRdma for Linux cgroup 'rdma' resource management (Linux 4.11).
836pub struct LinuxRdma {
837    #[serde(skip_serializing_if = "Option::is_none")]
838    /// Maximum number of HCA handles that can be opened. Default is "no
839    /// limit".
840    hca_handles: Option<u32>,
841
842    #[serde(skip_serializing_if = "Option::is_none")]
843    /// Maximum number of HCA objects that can be created. Default is "no
844    /// limit".
845    hca_objects: Option<u32>,
846}
847
848#[derive(
849    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, Hash, StrumDisplay,
850)]
851#[strum(serialize_all = "lowercase")]
852#[serde(rename_all = "snake_case")]
853/// Available Linux namespaces.
854pub enum LinuxNamespaceType {
855    #[strum(to_string = "mnt")]
856    /// Mount Namespace for isolating mount points
857    Mount = 0x00020000,
858
859    /// Cgroup Namespace for isolating cgroup hierarchies
860    Cgroup = 0x02000000,
861
862    /// Uts Namespace for isolating hostname and NIS domain name
863    Uts = 0x04000000,
864
865    /// Ipc Namespace for isolating System V, IPC, POSIX message queues
866    Ipc = 0x08000000,
867
868    /// User Namespace for isolating user and group  ids
869    User = 0x10000000,
870
871    /// PID Namespace for isolating process ids
872    #[default]
873    Pid = 0x20000000,
874
875    #[strum(to_string = "net")]
876    /// Network Namespace for isolating network devices, ports, stacks etc.
877    Network = 0x40000000,
878
879    /// Time Namespace for isolating the clocks
880    Time = 0x00000080,
881}
882
883impl TryFrom<&str> for LinuxNamespaceType {
884    type Error = OciSpecError;
885
886    fn try_from(namespace: &str) -> Result<Self, Self::Error> {
887        match namespace {
888            "mnt" | "mount" => Ok(LinuxNamespaceType::Mount),
889            "cgroup" => Ok(LinuxNamespaceType::Cgroup),
890            "uts" => Ok(LinuxNamespaceType::Uts),
891            "ipc" => Ok(LinuxNamespaceType::Ipc),
892            "user" => Ok(LinuxNamespaceType::User),
893            "pid" => Ok(LinuxNamespaceType::Pid),
894            "net" | "network" => Ok(LinuxNamespaceType::Network),
895            "time" => Ok(LinuxNamespaceType::Time),
896            _ => Err(oci_error(format!(
897                "unknown namespace {namespace}, could not convert"
898            ))),
899        }
900    }
901}
902
903#[derive(
904    Builder,
905    Clone,
906    CopyGetters,
907    Debug,
908    Default,
909    Deserialize,
910    Eq,
911    Getters,
912    Setters,
913    PartialEq,
914    Serialize,
915)]
916#[builder(
917    default,
918    pattern = "owned",
919    setter(into, strip_option),
920    build_fn(error = "OciSpecError")
921)]
922/// LinuxNamespace is the configuration for a Linux namespace.
923pub struct LinuxNamespace {
924    #[serde(rename = "type")]
925    #[getset(get_copy = "pub", set = "pub")]
926    /// Type is the type of namespace.
927    typ: LinuxNamespaceType,
928
929    #[serde(default, skip_serializing_if = "Option::is_none")]
930    #[getset(get = "pub", set = "pub")]
931    /// Path is a path to an existing namespace persisted on disk that can
932    /// be joined and is of the same type
933    path: Option<PathBuf>,
934}
935
936/// Utility function to get default namespaces.
937pub fn get_default_namespaces() -> Vec<LinuxNamespace> {
938    vec![
939        LinuxNamespace {
940            typ: LinuxNamespaceType::Pid,
941            path: Default::default(),
942        },
943        LinuxNamespace {
944            typ: LinuxNamespaceType::Network,
945            path: Default::default(),
946        },
947        LinuxNamespace {
948            typ: LinuxNamespaceType::Ipc,
949            path: Default::default(),
950        },
951        LinuxNamespace {
952            typ: LinuxNamespaceType::Uts,
953            path: Default::default(),
954        },
955        LinuxNamespace {
956            typ: LinuxNamespaceType::Mount,
957            path: Default::default(),
958        },
959        LinuxNamespace {
960            typ: LinuxNamespaceType::Cgroup,
961            path: Default::default(),
962        },
963    ]
964}
965
966#[derive(
967    Builder,
968    Clone,
969    CopyGetters,
970    Debug,
971    Default,
972    Deserialize,
973    Eq,
974    Getters,
975    MutGetters,
976    Setters,
977    PartialEq,
978    Serialize,
979)]
980#[serde(rename_all = "camelCase")]
981#[builder(
982    default,
983    pattern = "owned",
984    setter(into, strip_option),
985    build_fn(error = "OciSpecError")
986)]
987/// LinuxDevice represents the mknod information for a Linux special device
988/// file.
989pub struct LinuxDevice {
990    #[serde(default)]
991    #[getset(get_mut = "pub", get = "pub", set = "pub")]
992    /// Path to the device.
993    path: PathBuf,
994
995    #[serde(rename = "type")]
996    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
997    /// Device type, block, char, etc..
998    typ: LinuxDeviceType,
999
1000    #[serde(default)]
1001    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
1002    /// Major is the device's major number.
1003    major: i64,
1004
1005    #[serde(default)]
1006    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
1007    /// Minor is the device's minor number.
1008    minor: i64,
1009
1010    #[serde(default, skip_serializing_if = "Option::is_none")]
1011    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
1012    /// FileMode permission bits for the device.
1013    file_mode: Option<u32>,
1014
1015    #[serde(default, skip_serializing_if = "Option::is_none")]
1016    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
1017    /// UID of the device.
1018    uid: Option<u32>,
1019
1020    #[serde(default, skip_serializing_if = "Option::is_none")]
1021    #[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
1022    /// Gid of the device.
1023    gid: Option<u32>,
1024}
1025
1026impl From<&LinuxDevice> for LinuxDeviceCgroup {
1027    fn from(linux_device: &LinuxDevice) -> LinuxDeviceCgroup {
1028        LinuxDeviceCgroup {
1029            allow: true,
1030            typ: linux_device.typ.into(),
1031            major: Some(linux_device.major),
1032            minor: Some(linux_device.minor),
1033            access: "rwm".to_string().into(),
1034        }
1035    }
1036}
1037
1038#[derive(
1039    Builder,
1040    Clone,
1041    CopyGetters,
1042    Debug,
1043    Default,
1044    Deserialize,
1045    Eq,
1046    Getters,
1047    Setters,
1048    PartialEq,
1049    Serialize,
1050)]
1051#[serde(rename_all = "camelCase")]
1052#[builder(
1053    default,
1054    pattern = "owned",
1055    setter(into, strip_option),
1056    build_fn(error = "OciSpecError")
1057)]
1058/// LinuxSeccomp represents syscall restrictions.
1059pub struct LinuxSeccomp {
1060    #[getset(get_copy = "pub", set = "pub")]
1061    /// The default action to be done.
1062    default_action: LinuxSeccompAction,
1063
1064    #[serde(default, skip_serializing_if = "Option::is_none")]
1065    #[getset(get_copy = "pub", set = "pub")]
1066    /// The default error return code to use when the default action is SCMP_ACT_ERRNO.
1067    default_errno_ret: Option<u32>,
1068
1069    #[serde(default, skip_serializing_if = "Option::is_none")]
1070    #[getset(get = "pub", set = "pub")]
1071    /// Available architectures for the restriction.
1072    architectures: Option<Vec<Arch>>,
1073
1074    #[serde(default, skip_serializing_if = "Option::is_none")]
1075    #[getset(get = "pub", set = "pub")]
1076    /// Flags added to the seccomp restriction.
1077    flags: Option<Vec<LinuxSeccompFilterFlag>>,
1078
1079    #[serde(default, skip_serializing_if = "Option::is_none")]
1080    #[getset(get = "pub", set = "pub")]
1081    /// The unix domain socket path over which runtime will use for `SCMP_ACT_NOTIFY`.
1082    listener_path: Option<PathBuf>,
1083
1084    #[serde(default, skip_serializing_if = "Option::is_none")]
1085    #[getset(get = "pub", set = "pub")]
1086    /// An opaque data to pass to the seccomp agent.
1087    listener_metadata: Option<String>,
1088
1089    #[serde(default, skip_serializing_if = "Option::is_none")]
1090    #[getset(get = "pub", set = "pub")]
1091    /// The syscalls for the restriction.
1092    syscalls: Option<Vec<LinuxSyscall>>,
1093}
1094
1095#[derive(
1096    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1097)]
1098#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1099#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1100/// Available seccomp actions.
1101pub enum LinuxSeccompAction {
1102    /// Kill the thread, defined for backward compatibility.
1103    ScmpActKill,
1104
1105    /// Kill the thread
1106    ScmpActKillThread,
1107
1108    /// Kill the process.
1109    ScmpActKillProcess,
1110
1111    /// Throw a SIGSYS signal.
1112    ScmpActTrap,
1113
1114    /// Return the specified error code.
1115    ScmpActErrno,
1116
1117    /// Notifies userspace.
1118    ScmpActNotify,
1119
1120    /// Notify a tracing process with the specified value.
1121    ScmpActTrace,
1122
1123    /// Allow the syscall to be executed after the action has been logged.
1124    ScmpActLog,
1125
1126    /// Allow the syscall to be executed.
1127    #[default]
1128    ScmpActAllow,
1129}
1130
1131/// Converts [`LinuxSeccompAction`] to its `u32` representation.
1132impl From<LinuxSeccompAction> for u32 {
1133    fn from(action: LinuxSeccompAction) -> Self {
1134        action.as_u32(None)
1135    }
1136}
1137
1138impl LinuxSeccompAction {
1139    /// Converts the seccomp action to its u32 representation.
1140    ///
1141    /// The `errno_ret` parameter is used for actions that return an errno value.
1142    /// If the action is `ScmpActErrno` or `ScmpActTrace`, and `errno_ret` is provided,
1143    /// it will be included in the returned value.
1144    pub fn as_u32(&self, errno_ret: Option<u32>) -> u32 {
1145        match self {
1146            LinuxSeccompAction::ScmpActKill => 0x00000000,
1147            LinuxSeccompAction::ScmpActKillThread => 0x00000000,
1148            LinuxSeccompAction::ScmpActKillProcess => 0x80000000,
1149            LinuxSeccompAction::ScmpActTrap => 0x00030000,
1150            LinuxSeccompAction::ScmpActErrno => {
1151                if let Some(errno_ret) = errno_ret {
1152                    0x00050000 | errno_ret
1153                } else {
1154                    0x00050001
1155                }
1156            }
1157            LinuxSeccompAction::ScmpActNotify => 0x7fc00000,
1158            LinuxSeccompAction::ScmpActTrace => {
1159                if let Some(errno_ret) = errno_ret {
1160                    0x7ff00000 | errno_ret
1161                } else {
1162                    0x7ff00001
1163                }
1164            }
1165            LinuxSeccompAction::ScmpActLog => 0x7ffc0000,
1166            LinuxSeccompAction::ScmpActAllow => 0x7fff0000,
1167        }
1168    }
1169}
1170
1171#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
1172#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1173#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1174#[repr(u32)]
1175/// Available seccomp architectures.
1176pub enum Arch {
1177    /// The native architecture.
1178    ScmpArchNative = 0x00000000,
1179
1180    /// The x86 (32-bit) architecture.
1181    ScmpArchX86 = 0x40000003,
1182
1183    /// The x86-64 (64-bit) architecture.
1184    ScmpArchX86_64 = 0xc000003e,
1185
1186    /// The x32 (32-bit x86_64) architecture.
1187    ///
1188    /// This is different from the value used by the kernel because we need to
1189    /// be able to distinguish between x32 and x86_64.
1190    ScmpArchX32 = 0x4000003e,
1191
1192    /// The ARM architecture.
1193    ScmpArchArm = 0x40000028,
1194
1195    /// The AArch64 architecture.
1196    ScmpArchAarch64 = 0xc00000b7,
1197
1198    /// The MIPS architecture.
1199    ScmpArchMips = 0x00000008,
1200
1201    /// The MIPS64 architecture.
1202    ScmpArchMips64 = 0x80000008,
1203
1204    /// The MIPS64n32 architecture.
1205    ScmpArchMips64n32 = 0xa0000008,
1206
1207    /// The MIPSel architecture.
1208    ScmpArchMipsel = 0x40000008,
1209
1210    /// The MIPSel64 architecture.
1211    ScmpArchMipsel64 = 0xc0000008,
1212
1213    /// The MIPSel64n32 architecture.
1214    ScmpArchMipsel64n32 = 0xe0000008,
1215
1216    /// The PowerPC architecture.
1217    ScmpArchPpc = 0x00000014,
1218
1219    /// The PowerPC64 architecture.
1220    ScmpArchPpc64 = 0x80000015,
1221
1222    /// The PowerPC64le architecture.
1223    ScmpArchPpc64le = 0xc0000015,
1224
1225    /// The S390 architecture.
1226    ScmpArchS390 = 0x00000016,
1227
1228    /// The S390x architecture.
1229    ScmpArchS390x = 0x80000016,
1230
1231    /// The RISCV64 architecture.
1232    ScmpArchRiscv64 = 0xc00000f3,
1233}
1234
1235#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
1236#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1237#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1238/// Available seccomp filter flags.
1239pub enum LinuxSeccompFilterFlag {
1240    /// All filter return actions except SECCOMP_RET_ALLOW should be logged. An administrator may
1241    /// override this filter flag by preventing specific actions from being logged via the
1242    /// /proc/sys/kernel/seccomp/actions_logged file. (since Linux 4.14)
1243    SeccompFilterFlagLog,
1244
1245    /// When adding a new filter, synchronize all other threads of the calling process to the same
1246    /// seccomp filter tree. A "filter tree" is the ordered list of filters attached to a thread.
1247    /// (Attaching identical filters in separate seccomp() calls results in different filters from this
1248    /// perspective.)
1249    ///
1250    /// If any thread cannot synchronize to the same filter tree, the call will not attach the new
1251    /// seccomp filter, and will fail, returning the first thread ID found that cannot synchronize.
1252    /// Synchronization will fail if another thread in the same process is in SECCOMP_MODE_STRICT or if
1253    /// it has attached new seccomp filters to itself, diverging from the calling thread's filter tree.
1254    SeccompFilterFlagTsync,
1255
1256    /// Disable Speculative Store Bypass mitigation. (since Linux 4.17)
1257    SeccompFilterFlagSpecAllow,
1258
1259    /// Ensures the process is killable while waiting for notifications. (since linux 5.19)
1260    SeccompFilterFlagWaitKillableRecv,
1261}
1262
1263#[derive(
1264    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1265)]
1266#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1267#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1268#[repr(u32)]
1269/// The seccomp operator to be used for args.
1270pub enum LinuxSeccompOperator {
1271    /// Refers to the SCMP_CMP_NE operator (not equal).
1272    ScmpCmpNe = 1,
1273
1274    /// Refers to the SCMP_CMP_LT operator (less than).
1275    ScmpCmpLt = 2,
1276
1277    /// Refers to the SCMP_CMP_LE operator (less equal).
1278    ScmpCmpLe = 3,
1279
1280    /// Refers to the SCMP_CMP_EQ operator (equal to).
1281    #[default]
1282    ScmpCmpEq = 4,
1283
1284    /// Refers to the SCMP_CMP_GE operator (greater equal).
1285    ScmpCmpGe = 5,
1286
1287    /// Refers to the SCMP_CMP_GT operator (greater than).
1288    ScmpCmpGt = 6,
1289
1290    /// Refers to the SCMP_CMP_MASKED_EQ operator (masked equal).
1291    ScmpCmpMaskedEq = 7,
1292}
1293
1294#[derive(
1295    Builder,
1296    Clone,
1297    CopyGetters,
1298    Debug,
1299    Default,
1300    Deserialize,
1301    Eq,
1302    Getters,
1303    Setters,
1304    PartialEq,
1305    Serialize,
1306)]
1307#[serde(rename_all = "camelCase")]
1308#[builder(
1309    default,
1310    pattern = "owned",
1311    setter(into, strip_option),
1312    build_fn(error = "OciSpecError")
1313)]
1314/// LinuxSyscall is used to match a syscall in seccomp.
1315pub struct LinuxSyscall {
1316    #[getset(get = "pub", set = "pub")]
1317    /// The names of the syscalls.
1318    names: Vec<String>,
1319
1320    #[getset(get_copy = "pub", set = "pub")]
1321    /// The action to be done for the syscalls.
1322    action: LinuxSeccompAction,
1323
1324    #[serde(default, skip_serializing_if = "Option::is_none")]
1325    #[getset(get_copy = "pub", set = "pub")]
1326    /// The error return value.
1327    errno_ret: Option<u32>,
1328
1329    #[serde(default, skip_serializing_if = "Option::is_none")]
1330    #[getset(get = "pub", set = "pub")]
1331    /// The arguments for the syscalls.
1332    args: Option<Vec<LinuxSeccompArg>>,
1333}
1334
1335#[derive(
1336    Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
1337)]
1338#[serde(rename_all = "camelCase")]
1339#[builder(
1340    default,
1341    pattern = "owned",
1342    setter(into, strip_option),
1343    build_fn(error = "OciSpecError")
1344)]
1345#[getset(get_copy = "pub", set = "pub")]
1346/// LinuxSeccompArg used for matching specific syscall arguments in seccomp.
1347pub struct LinuxSeccompArg {
1348    /// The index of the argument.
1349    index: usize,
1350
1351    /// The value of the argument.
1352    value: u64,
1353
1354    #[serde(default, skip_serializing_if = "Option::is_none")]
1355    /// The second value of the argument.
1356    value_two: Option<u64>,
1357
1358    /// The operator for the argument.
1359    op: LinuxSeccompOperator,
1360}
1361
1362/// Default masks paths, cannot read these host files.
1363pub fn get_default_maskedpaths() -> Vec<String> {
1364    vec![
1365        // For example now host interfaces such as
1366        // bluetooth cannot be accessed due to /proc/acpi
1367        "/proc/acpi".to_string(),
1368        "/proc/asound".to_string(),
1369        "/proc/kcore".to_string(),
1370        "/proc/keys".to_string(),
1371        "/proc/latency_stats".to_string(),
1372        "/proc/timer_list".to_string(),
1373        "/proc/timer_stats".to_string(),
1374        "/proc/sched_debug".to_string(),
1375        "/sys/firmware".to_string(),
1376        "/proc/scsi".to_string(),
1377    ]
1378}
1379
1380/// Default readonly paths, for example most containers shouldn't have permission to write to
1381/// `/proc/sys`.
1382pub fn get_default_readonly_paths() -> Vec<String> {
1383    vec![
1384        "/proc/bus".to_string(),
1385        "/proc/fs".to_string(),
1386        "/proc/irq".to_string(),
1387        "/proc/sys".to_string(),
1388        "/proc/sysrq-trigger".to_string(),
1389    ]
1390}
1391
1392#[derive(
1393    Builder,
1394    Clone,
1395    Debug,
1396    Default,
1397    Deserialize,
1398    Eq,
1399    Getters,
1400    MutGetters,
1401    Setters,
1402    PartialEq,
1403    Serialize,
1404)]
1405#[serde(rename_all = "camelCase")]
1406#[builder(
1407    default,
1408    pattern = "owned",
1409    setter(into, strip_option),
1410    build_fn(error = "OciSpecError")
1411)]
1412#[getset(get_mut = "pub", get = "pub", set = "pub")]
1413/// LinuxIntelRdt has container runtime resource constraints for Intel RDT CAT and MBA
1414/// features and flags enabling Intel RDT CMT and MBM features.
1415/// Intel RDT features are available in Linux 4.14 and newer kernel versions.
1416pub struct LinuxIntelRdt {
1417    #[serde(default, skip_serializing_if = "Option::is_none", rename = "closID")]
1418    /// The identity for RDT Class of Service.
1419    clos_id: Option<String>,
1420
1421    #[serde(default, skip_serializing_if = "Option::is_none")]
1422    /// The schema for L3 cache id and capacity bitmask (CBM).
1423    /// Format: "L3:&lt;cache_id0&gt;=&lt;cbm0&gt;;&lt;cache_id1&gt;=&lt;cbm1&gt;;..."
1424    l3_cache_schema: Option<String>,
1425
1426    #[serde(default, skip_serializing_if = "Option::is_none")]
1427    /// The schema of memory bandwidth per L3 cache id.
1428    /// Format: "MB:&lt;cache_id0&gt;=bandwidth0;&lt;cache_id1&gt;=bandwidth1;..."
1429    /// The unit of memory bandwidth is specified in "percentages" by
1430    /// default, and in "MBps" if MBA Software Controller is
1431    /// enabled.
1432    mem_bw_schema: Option<String>,
1433
1434    #[serde(default, skip_serializing_if = "Option::is_none")]
1435    /// EnableCMT is the flag to indicate if the Intel RDT CMT is enabled. CMT (Cache Monitoring Technology) supports monitoring of
1436    /// the last-level cache (LLC) occupancy for the container.
1437    enable_cmt: Option<bool>,
1438
1439    #[serde(default, skip_serializing_if = "Option::is_none")]
1440    /// EnableMBM is the flag to indicate if the Intel RDT MBM is enabled. MBM (Memory Bandwidth Monitoring) supports monitoring of
1441    /// total and local memory bandwidth for the container.
1442    enable_mbm: Option<bool>,
1443}
1444
1445#[derive(
1446    Builder,
1447    Clone,
1448    CopyGetters,
1449    Debug,
1450    Default,
1451    Deserialize,
1452    Eq,
1453    Getters,
1454    Setters,
1455    PartialEq,
1456    Serialize,
1457)]
1458#[builder(
1459    default,
1460    pattern = "owned",
1461    setter(into, strip_option),
1462    build_fn(error = "OciSpecError")
1463)]
1464/// LinuxPersonality represents the Linux personality syscall input.
1465pub struct LinuxPersonality {
1466    #[getset(get_copy = "pub", set = "pub")]
1467    /// Domain for the personality.
1468    domain: LinuxPersonalityDomain,
1469
1470    #[serde(default, skip_serializing_if = "Option::is_none")]
1471    #[getset(get = "pub", set = "pub")]
1472    /// Additional flags
1473    flags: Option<Vec<String>>,
1474}
1475
1476#[derive(
1477    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1478)]
1479/// Define domain and flags for LinuxPersonality.
1480pub enum LinuxPersonalityDomain {
1481    #[serde(rename = "LINUX")]
1482    #[strum(serialize = "LINUX")]
1483    /// PerLinux is the standard Linux personality.
1484    #[default]
1485    PerLinux,
1486
1487    #[serde(rename = "LINUX32")]
1488    #[strum(serialize = "LINUX32")]
1489    /// PerLinux32 sets personality to 32 bit.
1490    PerLinux32,
1491}
1492
1493#[derive(
1494    Builder,
1495    Clone,
1496    CopyGetters,
1497    Debug,
1498    Deserialize,
1499    Eq,
1500    Getters,
1501    MutGetters,
1502    Setters,
1503    PartialEq,
1504    Serialize,
1505)]
1506#[serde(rename_all = "camelCase")]
1507#[builder(
1508    pattern = "owned",
1509    setter(into, strip_option),
1510    build_fn(error = "OciSpecError")
1511)]
1512/// LinuxMemoryPolicy represents input for the set_mempolicy syscall.
1513pub struct LinuxMemoryPolicy {
1514    #[getset(get_copy = "pub", set = "pub")]
1515    /// Mode for the set_mempolicy syscall.
1516    mode: MemoryPolicyModeType,
1517
1518    #[serde(default, skip_serializing_if = "Option::is_none")]
1519    #[getset(get = "pub", set = "pub")]
1520    /// Nodes representing the nodemask for the set_mempolicy syscall in comma separated ranges format.
1521    /// Format: "&lt;node0&gt;-&lt;node1&gt;,&lt;node2&gt;,&lt;node3&gt;-&lt;node4&gt;,..."
1522    nodes: Option<String>,
1523
1524    #[serde(default, skip_serializing_if = "Option::is_none")]
1525    #[getset(get = "pub", get_mut = "pub", set = "pub")]
1526    /// Flags for the set_mempolicy syscall.
1527    flags: Option<Vec<MemoryPolicyFlagType>>,
1528}
1529
1530impl Default for LinuxMemoryPolicy {
1531    fn default() -> Self {
1532        Self {
1533            mode: MemoryPolicyModeType::MpolDefault,
1534            nodes: None,
1535            flags: None,
1536        }
1537    }
1538}
1539
1540#[derive(
1541    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1542)]
1543/// MemoryPolicyModeType defines the memory policy mode.
1544pub enum MemoryPolicyModeType {
1545    #[serde(rename = "MPOL_DEFAULT")]
1546    #[strum(serialize = "MPOL_DEFAULT")]
1547    /// MpolDefault - Default NUMA policy.
1548    #[default]
1549    MpolDefault,
1550
1551    #[serde(rename = "MPOL_BIND")]
1552    #[strum(serialize = "MPOL_BIND")]
1553    /// MpolBind - Bind memory allocation to specific nodes.
1554    MpolBind,
1555
1556    #[serde(rename = "MPOL_INTERLEAVE")]
1557    #[strum(serialize = "MPOL_INTERLEAVE")]
1558    /// MpolInterleave - Interleave memory allocation across nodes.
1559    MpolInterleave,
1560
1561    #[serde(rename = "MPOL_WEIGHTED_INTERLEAVE")]
1562    #[strum(serialize = "MPOL_WEIGHTED_INTERLEAVE")]
1563    /// MpolWeightedInterleave - Weighted interleave memory allocation across nodes.
1564    MpolWeightedInterleave,
1565
1566    #[serde(rename = "MPOL_PREFERRED")]
1567    #[strum(serialize = "MPOL_PREFERRED")]
1568    /// MpolPreferred - Prefer memory allocation from specific nodes.
1569    MpolPreferred,
1570
1571    #[serde(rename = "MPOL_PREFERRED_MANY")]
1572    #[strum(serialize = "MPOL_PREFERRED_MANY")]
1573    /// MpolPreferredMany - Prefer memory allocation from multiple nodes.
1574    MpolPreferredMany,
1575
1576    #[serde(rename = "MPOL_LOCAL")]
1577    #[strum(serialize = "MPOL_LOCAL")]
1578    /// MpolLocal - Local node memory allocation.
1579    MpolLocal,
1580}
1581
1582#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
1583/// MemoryPolicyFlagType defines the memory policy flags.
1584pub enum MemoryPolicyFlagType {
1585    #[serde(rename = "MPOL_F_NUMA_BALANCING")]
1586    #[strum(serialize = "MPOL_F_NUMA_BALANCING")]
1587    /// MpolFNumaBalancing - Enable NUMA balancing.
1588    MpolFNumaBalancing,
1589
1590    #[serde(rename = "MPOL_F_RELATIVE_NODES")]
1591    #[strum(serialize = "MPOL_F_RELATIVE_NODES")]
1592    /// MpolFRelativeNodes - Use relative node numbers.
1593    MpolFRelativeNodes,
1594
1595    #[serde(rename = "MPOL_F_STATIC_NODES")]
1596    #[strum(serialize = "MPOL_F_STATIC_NODES")]
1597    /// MpolFStaticNodes - Use static node numbers.
1598    MpolFStaticNodes,
1599}
1600
1601#[derive(
1602    Builder,
1603    Clone,
1604    CopyGetters,
1605    Debug,
1606    Default,
1607    Deserialize,
1608    Eq,
1609    Getters,
1610    Setters,
1611    PartialEq,
1612    Serialize,
1613)]
1614#[builder(
1615    default,
1616    pattern = "owned",
1617    setter(into, strip_option),
1618    build_fn(error = "OciSpecError")
1619)]
1620/// LinuxTimeOffset specifies the offset for Time Namespace
1621pub struct LinuxTimeOffset {
1622    /// Secs is the offset of clock (in secs) in the container
1623    #[serde(default, skip_serializing_if = "Option::is_none")]
1624    #[getset(get_copy = "pub", set = "pub")]
1625    secs: Option<i64>,
1626    /// Nanosecs is the additional offset for Secs (in nanosecs)
1627    #[serde(default, skip_serializing_if = "Option::is_none")]
1628    #[getset(get_copy = "pub", set = "pub")]
1629    nanosecs: Option<u32>,
1630}
1631
1632#[cfg(feature = "proptests")]
1633use quickcheck::{Arbitrary, Gen};
1634
1635#[cfg(feature = "proptests")]
1636fn some_none_generator_util<T: Arbitrary>(g: &mut Gen) -> Option<T> {
1637    let choice = g.choose(&[true, false]).unwrap();
1638    match choice {
1639        false => None,
1640        true => Some(T::arbitrary(g)),
1641    }
1642}
1643
1644#[cfg(feature = "proptests")]
1645impl Arbitrary for LinuxDeviceCgroup {
1646    fn arbitrary(g: &mut Gen) -> LinuxDeviceCgroup {
1647        let typ_choices = ["a", "b", "c", "u", "p"];
1648
1649        let typ_chosen = g.choose(&typ_choices).unwrap();
1650
1651        let typ = match typ_chosen.to_string().as_str() {
1652            "a" => LinuxDeviceType::A,
1653            "b" => LinuxDeviceType::B,
1654            "c" => LinuxDeviceType::C,
1655            "u" => LinuxDeviceType::U,
1656            "p" => LinuxDeviceType::P,
1657            _ => LinuxDeviceType::A,
1658        };
1659
1660        let access_choices = ["rwm", "m"];
1661        LinuxDeviceCgroup {
1662            allow: bool::arbitrary(g),
1663            typ: typ.into(),
1664            major: some_none_generator_util::<i64>(g),
1665            minor: some_none_generator_util::<i64>(g),
1666            access: g.choose(&access_choices).unwrap().to_string().into(),
1667        }
1668    }
1669}
1670
1671#[cfg(feature = "proptests")]
1672impl Arbitrary for LinuxMemory {
1673    fn arbitrary(g: &mut Gen) -> LinuxMemory {
1674        LinuxMemory {
1675            kernel: some_none_generator_util::<i64>(g),
1676            kernel_tcp: some_none_generator_util::<i64>(g),
1677            limit: some_none_generator_util::<i64>(g),
1678            reservation: some_none_generator_util::<i64>(g),
1679            swap: some_none_generator_util::<i64>(g),
1680            swappiness: some_none_generator_util::<u64>(g),
1681            disable_oom_killer: some_none_generator_util::<bool>(g),
1682            use_hierarchy: some_none_generator_util::<bool>(g),
1683            check_before_update: some_none_generator_util::<bool>(g),
1684        }
1685    }
1686}
1687
1688#[cfg(feature = "proptests")]
1689impl Arbitrary for LinuxHugepageLimit {
1690    fn arbitrary(g: &mut Gen) -> LinuxHugepageLimit {
1691        let unit_choice = ["KB", "MB", "GB"];
1692        let unit = g.choose(&unit_choice).unwrap();
1693        let page_size = u64::arbitrary(g).to_string() + unit;
1694
1695        LinuxHugepageLimit {
1696            page_size,
1697            limit: i64::arbitrary(g),
1698        }
1699    }
1700}
1701
1702#[cfg(test)]
1703mod tests {
1704    use super::*;
1705
1706    // LinuxDeviceType test cases
1707    #[test]
1708    fn device_type_enum_to_str() {
1709        let type_a = LinuxDeviceType::A;
1710        assert_eq!(type_a.as_str(), "a");
1711
1712        let type_b = LinuxDeviceType::B;
1713        assert_eq!(type_b.as_str(), "b");
1714
1715        let type_c = LinuxDeviceType::C;
1716        assert_eq!(type_c.as_str(), "c");
1717    }
1718
1719    #[test]
1720    fn device_type_string_to_enum() {
1721        let devtype_str = "a";
1722        let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
1723        assert_eq!(devtype_enum, LinuxDeviceType::A);
1724
1725        let devtype_str = "b";
1726        let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
1727        assert_eq!(devtype_enum, LinuxDeviceType::B);
1728
1729        let devtype_str = "c";
1730        let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
1731        assert_eq!(devtype_enum, LinuxDeviceType::C);
1732
1733        let invalid_devtype_str = "x";
1734        let unknown_devtype = invalid_devtype_str.parse::<LinuxDeviceType>();
1735        assert!(unknown_devtype.is_err());
1736    }
1737
1738    // LinuxNamespaceType test cases
1739    #[test]
1740    fn ns_type_enum_to_string() {
1741        let type_a = LinuxNamespaceType::Network;
1742        assert_eq!(type_a.to_string(), "net");
1743
1744        let type_b = LinuxNamespaceType::Mount;
1745        assert_eq!(type_b.to_string(), "mnt");
1746
1747        let type_c = LinuxNamespaceType::Ipc;
1748        assert_eq!(type_c.to_string(), "ipc");
1749    }
1750
1751    #[test]
1752    fn ns_type_string_to_enum() {
1753        let nstype_str = "net";
1754        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1755        assert_eq!(nstype_enum, LinuxNamespaceType::Network);
1756
1757        let nstype_str = "network";
1758        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1759        assert_eq!(nstype_enum, LinuxNamespaceType::Network);
1760
1761        let nstype_str = "ipc";
1762        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1763        assert_eq!(nstype_enum, LinuxNamespaceType::Ipc);
1764
1765        let nstype_str = "cgroup";
1766        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1767        assert_eq!(nstype_enum, LinuxNamespaceType::Cgroup);
1768
1769        let nstype_str = "mount";
1770        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1771        assert_eq!(nstype_enum, LinuxNamespaceType::Mount);
1772
1773        let invalid_nstype_str = "xxx";
1774        let unknown_nstype = LinuxNamespaceType::try_from(invalid_nstype_str);
1775        assert!(unknown_nstype.is_err());
1776    }
1777
1778    // LinuxSeccompAction test cases
1779    #[test]
1780    fn seccomp_action_enum_to_string() {
1781        let type_a = LinuxSeccompAction::ScmpActKill;
1782        assert_eq!(type_a.to_string(), "SCMP_ACT_KILL");
1783
1784        let type_b = LinuxSeccompAction::ScmpActAllow;
1785        assert_eq!(type_b.to_string(), "SCMP_ACT_ALLOW");
1786
1787        let type_c = LinuxSeccompAction::ScmpActNotify;
1788        assert_eq!(type_c.to_string(), "SCMP_ACT_NOTIFY");
1789    }
1790
1791    #[test]
1792    fn seccomp_action_string_to_enum() {
1793        let action_str = "SCMP_ACT_KILL";
1794        let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
1795        assert_eq!(action_enum, LinuxSeccompAction::ScmpActKill);
1796
1797        let action_str = "SCMP_ACT_ALLOW";
1798        let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
1799        assert_eq!(action_enum, LinuxSeccompAction::ScmpActAllow);
1800
1801        let action_str = "SCMP_ACT_NOTIFY";
1802        let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
1803        assert_eq!(action_enum, LinuxSeccompAction::ScmpActNotify);
1804
1805        let invalid_action_str = "x";
1806        let unknown_action = invalid_action_str.parse::<LinuxSeccompAction>();
1807        assert!(unknown_action.is_err());
1808    }
1809
1810    // LinuxSeccomp Arch test cases
1811    #[test]
1812    fn seccomp_arch_enum_to_string() {
1813        let type_a = Arch::ScmpArchX86_64;
1814        assert_eq!(type_a.to_string(), "SCMP_ARCH_X86_64");
1815
1816        let type_b = Arch::ScmpArchAarch64;
1817        assert_eq!(type_b.to_string(), "SCMP_ARCH_AARCH64");
1818
1819        let type_c = Arch::ScmpArchPpc64le;
1820        assert_eq!(type_c.to_string(), "SCMP_ARCH_PPC64LE");
1821    }
1822
1823    #[test]
1824    fn seccomp_arch_string_to_enum() {
1825        let arch_type_str = "SCMP_ARCH_X86_64";
1826        let arch_type_enum: Arch = arch_type_str.parse().unwrap();
1827        assert_eq!(arch_type_enum, Arch::ScmpArchX86_64);
1828
1829        let arch_type_str = "SCMP_ARCH_AARCH64";
1830        let arch_type_enum: Arch = arch_type_str.parse().unwrap();
1831        assert_eq!(arch_type_enum, Arch::ScmpArchAarch64);
1832
1833        let arch_type_str = "SCMP_ARCH_PPC64LE";
1834        let arch_type_enum: Arch = arch_type_str.parse().unwrap();
1835        assert_eq!(arch_type_enum, Arch::ScmpArchPpc64le);
1836
1837        let invalid_arch_str = "x";
1838        let unknown_arch = invalid_arch_str.parse::<Arch>();
1839        assert!(unknown_arch.is_err());
1840    }
1841
1842    // LinuxSeccompFilterFlag test cases
1843    #[test]
1844    fn seccomp_filter_flag_enum_to_string() {
1845        let type_a = LinuxSeccompFilterFlag::SeccompFilterFlagLog;
1846        assert_eq!(type_a.to_string(), "SECCOMP_FILTER_FLAG_LOG");
1847
1848        let type_b = LinuxSeccompFilterFlag::SeccompFilterFlagTsync;
1849        assert_eq!(type_b.to_string(), "SECCOMP_FILTER_FLAG_TSYNC");
1850
1851        let type_c = LinuxSeccompFilterFlag::SeccompFilterFlagSpecAllow;
1852        assert_eq!(type_c.to_string(), "SECCOMP_FILTER_FLAG_SPEC_ALLOW");
1853
1854        let type_d = LinuxSeccompFilterFlag::SeccompFilterFlagWaitKillableRecv;
1855        assert_eq!(type_d.to_string(), "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV");
1856    }
1857
1858    #[test]
1859    fn seccomp_filter_flag_string_to_enum() {
1860        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_LOG";
1861        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1862        assert_eq!(
1863            filter_flag_type_enum,
1864            LinuxSeccompFilterFlag::SeccompFilterFlagLog
1865        );
1866
1867        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_TSYNC";
1868        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1869        assert_eq!(
1870            filter_flag_type_enum,
1871            LinuxSeccompFilterFlag::SeccompFilterFlagTsync
1872        );
1873
1874        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_SPEC_ALLOW";
1875        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1876        assert_eq!(
1877            filter_flag_type_enum,
1878            LinuxSeccompFilterFlag::SeccompFilterFlagSpecAllow
1879        );
1880
1881        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV";
1882        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1883        assert_eq!(
1884            filter_flag_type_enum,
1885            LinuxSeccompFilterFlag::SeccompFilterFlagWaitKillableRecv
1886        );
1887
1888        let invalid_filter_flag_str = "x";
1889        let unknown_arch = invalid_filter_flag_str.parse::<LinuxSeccompFilterFlag>();
1890        assert!(unknown_arch.is_err());
1891    }
1892
1893    // LinuxSeccompOperator test cases
1894    #[test]
1895    fn seccomp_operator_enum_to_string() {
1896        let type_a = LinuxSeccompOperator::ScmpCmpNe;
1897        assert_eq!(type_a.to_string(), "SCMP_CMP_NE");
1898
1899        let type_b = LinuxSeccompOperator::ScmpCmpMaskedEq;
1900        assert_eq!(type_b.to_string(), "SCMP_CMP_MASKED_EQ");
1901
1902        let type_c = LinuxSeccompOperator::ScmpCmpGt;
1903        assert_eq!(type_c.to_string(), "SCMP_CMP_GT");
1904    }
1905
1906    // LinuxSeccompAction test cases
1907    #[test]
1908    fn seccomp_action_as_u32() {
1909        let action = LinuxSeccompAction::ScmpActErrno;
1910        assert_eq!(action.as_u32(Option::None), 0x00050001);
1911
1912        let action = LinuxSeccompAction::ScmpActErrno;
1913        assert_eq!(action.as_u32(Option::Some(10)), 0x00050000 | 10);
1914
1915        let action = LinuxSeccompAction::ScmpActTrace;
1916        assert_eq!(action.as_u32(Option::None), 0x7ff00001);
1917
1918        let action = LinuxSeccompAction::ScmpActTrace;
1919        assert_eq!(action.as_u32(Option::Some(10)), 0x7ff00000 | 10);
1920    }
1921
1922    #[test]
1923    fn seccomp_operator_string_to_enum() {
1924        let seccomp_operator_str = "SCMP_CMP_GT";
1925        let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
1926        assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpGt);
1927
1928        let seccomp_operator_str = "SCMP_CMP_NE";
1929        let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
1930        assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpNe);
1931
1932        let seccomp_operator_str = "SCMP_CMP_MASKED_EQ";
1933        let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
1934        assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpMaskedEq);
1935
1936        let invalid_seccomp_operator_str = "x";
1937        let unknown_operator = invalid_seccomp_operator_str.parse::<LinuxSeccompOperator>();
1938        assert!(unknown_operator.is_err());
1939    }
1940
1941    // MemoryPolicyModeType test cases
1942    #[test]
1943    fn memory_policy_mode_enum_to_string() {
1944        let mode_a = MemoryPolicyModeType::MpolDefault;
1945        assert_eq!(mode_a.to_string(), "MPOL_DEFAULT");
1946
1947        let mode_b = MemoryPolicyModeType::MpolBind;
1948        assert_eq!(mode_b.to_string(), "MPOL_BIND");
1949
1950        let mode_c = MemoryPolicyModeType::MpolInterleave;
1951        assert_eq!(mode_c.to_string(), "MPOL_INTERLEAVE");
1952
1953        let mode_d = MemoryPolicyModeType::MpolWeightedInterleave;
1954        assert_eq!(mode_d.to_string(), "MPOL_WEIGHTED_INTERLEAVE");
1955
1956        let mode_e = MemoryPolicyModeType::MpolPreferred;
1957        assert_eq!(mode_e.to_string(), "MPOL_PREFERRED");
1958
1959        let mode_f = MemoryPolicyModeType::MpolPreferredMany;
1960        assert_eq!(mode_f.to_string(), "MPOL_PREFERRED_MANY");
1961
1962        let mode_g = MemoryPolicyModeType::MpolLocal;
1963        assert_eq!(mode_g.to_string(), "MPOL_LOCAL");
1964    }
1965
1966    #[test]
1967    fn memory_policy_mode_string_to_enum() {
1968        let mode_str = "MPOL_INTERLEAVE";
1969        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1970        assert_eq!(mode_enum, MemoryPolicyModeType::MpolInterleave);
1971
1972        let mode_str = "MPOL_BIND";
1973        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1974        assert_eq!(mode_enum, MemoryPolicyModeType::MpolBind);
1975
1976        let mode_str = "MPOL_DEFAULT";
1977        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1978        assert_eq!(mode_enum, MemoryPolicyModeType::MpolDefault);
1979
1980        let mode_str = "MPOL_WEIGHTED_INTERLEAVE";
1981        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1982        assert_eq!(mode_enum, MemoryPolicyModeType::MpolWeightedInterleave);
1983
1984        let mode_str = "MPOL_PREFERRED";
1985        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1986        assert_eq!(mode_enum, MemoryPolicyModeType::MpolPreferred);
1987
1988        let mode_str = "MPOL_PREFERRED_MANY";
1989        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1990        assert_eq!(mode_enum, MemoryPolicyModeType::MpolPreferredMany);
1991
1992        let mode_str = "MPOL_LOCAL";
1993        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1994        assert_eq!(mode_enum, MemoryPolicyModeType::MpolLocal);
1995
1996        let invalid_mode_str = "INVALID_MODE";
1997        let unknown_mode = invalid_mode_str.parse::<MemoryPolicyModeType>();
1998        assert!(unknown_mode.is_err());
1999    }
2000
2001    // MemoryPolicyFlagType test cases
2002    #[test]
2003    fn memory_policy_flag_enum_to_string() {
2004        let flag_a = MemoryPolicyFlagType::MpolFNumaBalancing;
2005        assert_eq!(flag_a.to_string(), "MPOL_F_NUMA_BALANCING");
2006
2007        let flag_b = MemoryPolicyFlagType::MpolFRelativeNodes;
2008        assert_eq!(flag_b.to_string(), "MPOL_F_RELATIVE_NODES");
2009
2010        let flag_c = MemoryPolicyFlagType::MpolFStaticNodes;
2011        assert_eq!(flag_c.to_string(), "MPOL_F_STATIC_NODES");
2012    }
2013
2014    #[test]
2015    fn memory_policy_flag_string_to_enum() {
2016        let flag_str = "MPOL_F_NUMA_BALANCING";
2017        let flag_enum: MemoryPolicyFlagType = flag_str.parse().unwrap();
2018        assert_eq!(flag_enum, MemoryPolicyFlagType::MpolFNumaBalancing);
2019
2020        let flag_str = "MPOL_F_RELATIVE_NODES";
2021        let flag_enum: MemoryPolicyFlagType = flag_str.parse().unwrap();
2022        assert_eq!(flag_enum, MemoryPolicyFlagType::MpolFRelativeNodes);
2023
2024        let flag_str = "MPOL_F_STATIC_NODES";
2025        let flag_enum: MemoryPolicyFlagType = flag_str.parse().unwrap();
2026        assert_eq!(flag_enum, MemoryPolicyFlagType::MpolFStaticNodes);
2027
2028        let invalid_flag_str = "INVALID_FLAG";
2029        let unknown_flag = invalid_flag_str.parse::<MemoryPolicyFlagType>();
2030        assert!(unknown_flag.is_err());
2031    }
2032
2033    #[test]
2034    fn test_linux_memory_policy_serialization() {
2035        let memory_policy = LinuxMemoryPolicy {
2036            mode: MemoryPolicyModeType::MpolInterleave,
2037            nodes: Some("0-3,7".to_string()),
2038            flags: Some(vec![
2039                MemoryPolicyFlagType::MpolFStaticNodes,
2040                MemoryPolicyFlagType::MpolFRelativeNodes,
2041            ]),
2042        };
2043
2044        let json = serde_json::to_string(&memory_policy).unwrap();
2045        let deserialized: LinuxMemoryPolicy = serde_json::from_str(&json).unwrap();
2046
2047        assert_eq!(deserialized.mode, MemoryPolicyModeType::MpolInterleave);
2048        assert_eq!(deserialized.nodes, Some("0-3,7".to_string()));
2049        assert_eq!(
2050            deserialized.flags,
2051            Some(vec![
2052                MemoryPolicyFlagType::MpolFStaticNodes,
2053                MemoryPolicyFlagType::MpolFRelativeNodes,
2054            ])
2055        );
2056    }
2057
2058    #[test]
2059    fn test_linux_memory_policy_default() {
2060        let memory_policy = LinuxMemoryPolicy::default();
2061        assert_eq!(memory_policy.mode, MemoryPolicyModeType::MpolDefault);
2062        assert_eq!(memory_policy.nodes, None);
2063        assert_eq!(memory_policy.flags, None);
2064    }
2065}