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
1131impl From<LinuxSeccompAction> for u32 {
1132    fn from(action: LinuxSeccompAction) -> Self {
1133        match action {
1134            LinuxSeccompAction::ScmpActKill => 0x00000000,
1135            LinuxSeccompAction::ScmpActKillThread => 0x00000000,
1136            LinuxSeccompAction::ScmpActKillProcess => 0x80000000,
1137            LinuxSeccompAction::ScmpActTrap => 0x00030000,
1138            LinuxSeccompAction::ScmpActErrno => 0x00050001,
1139            LinuxSeccompAction::ScmpActNotify => 0x7fc00000,
1140            LinuxSeccompAction::ScmpActTrace => 0x7ff00001,
1141            LinuxSeccompAction::ScmpActLog => 0x7ffc0000,
1142            LinuxSeccompAction::ScmpActAllow => 0x7fff0000,
1143        }
1144    }
1145}
1146
1147#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
1148#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1149#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1150#[repr(u32)]
1151/// Available seccomp architectures.
1152pub enum Arch {
1153    /// The native architecture.
1154    ScmpArchNative = 0x00000000,
1155
1156    /// The x86 (32-bit) architecture.
1157    ScmpArchX86 = 0x40000003,
1158
1159    /// The x86-64 (64-bit) architecture.
1160    ScmpArchX86_64 = 0xc000003e,
1161
1162    /// The x32 (32-bit x86_64) architecture.
1163    ///
1164    /// This is different from the value used by the kernel because we need to
1165    /// be able to distinguish between x32 and x86_64.
1166    ScmpArchX32 = 0x4000003e,
1167
1168    /// The ARM architecture.
1169    ScmpArchArm = 0x40000028,
1170
1171    /// The AArch64 architecture.
1172    ScmpArchAarch64 = 0xc00000b7,
1173
1174    /// The MIPS architecture.
1175    ScmpArchMips = 0x00000008,
1176
1177    /// The MIPS64 architecture.
1178    ScmpArchMips64 = 0x80000008,
1179
1180    /// The MIPS64n32 architecture.
1181    ScmpArchMips64n32 = 0xa0000008,
1182
1183    /// The MIPSel architecture.
1184    ScmpArchMipsel = 0x40000008,
1185
1186    /// The MIPSel64 architecture.
1187    ScmpArchMipsel64 = 0xc0000008,
1188
1189    /// The MIPSel64n32 architecture.
1190    ScmpArchMipsel64n32 = 0xe0000008,
1191
1192    /// The PowerPC architecture.
1193    ScmpArchPpc = 0x00000014,
1194
1195    /// The PowerPC64 architecture.
1196    ScmpArchPpc64 = 0x80000015,
1197
1198    /// The PowerPC64le architecture.
1199    ScmpArchPpc64le = 0xc0000015,
1200
1201    /// The S390 architecture.
1202    ScmpArchS390 = 0x00000016,
1203
1204    /// The S390x architecture.
1205    ScmpArchS390x = 0x80000016,
1206
1207    /// The RISCV64 architecture.
1208    ScmpArchRiscv64 = 0xc00000f3,
1209}
1210
1211#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
1212#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1213#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1214/// Available seccomp filter flags.
1215pub enum LinuxSeccompFilterFlag {
1216    /// All filter return actions except SECCOMP_RET_ALLOW should be logged. An administrator may
1217    /// override this filter flag by preventing specific actions from being logged via the
1218    /// /proc/sys/kernel/seccomp/actions_logged file. (since Linux 4.14)
1219    SeccompFilterFlagLog,
1220
1221    /// When adding a new filter, synchronize all other threads of the calling process to the same
1222    /// seccomp filter tree. A "filter tree" is the ordered list of filters attached to a thread.
1223    /// (Attaching identical filters in separate seccomp() calls results in different filters from this
1224    /// perspective.)
1225    ///
1226    /// If any thread cannot synchronize to the same filter tree, the call will not attach the new
1227    /// seccomp filter, and will fail, returning the first thread ID found that cannot synchronize.
1228    /// Synchronization will fail if another thread in the same process is in SECCOMP_MODE_STRICT or if
1229    /// it has attached new seccomp filters to itself, diverging from the calling thread's filter tree.
1230    SeccompFilterFlagTsync,
1231
1232    /// Disable Speculative Store Bypass mitigation. (since Linux 4.17)
1233    SeccompFilterFlagSpecAllow,
1234}
1235
1236#[derive(
1237    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1238)]
1239#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
1240#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1241#[repr(u32)]
1242/// The seccomp operator to be used for args.
1243pub enum LinuxSeccompOperator {
1244    /// Refers to the SCMP_CMP_NE operator (not equal).
1245    ScmpCmpNe = 1,
1246
1247    /// Refers to the SCMP_CMP_LT operator (less than).
1248    ScmpCmpLt = 2,
1249
1250    /// Refers to the SCMP_CMP_LE operator (less equal).
1251    ScmpCmpLe = 3,
1252
1253    /// Refers to the SCMP_CMP_EQ operator (equal to).
1254    #[default]
1255    ScmpCmpEq = 4,
1256
1257    /// Refers to the SCMP_CMP_GE operator (greater equal).
1258    ScmpCmpGe = 5,
1259
1260    /// Refers to the SCMP_CMP_GT operator (greater than).
1261    ScmpCmpGt = 6,
1262
1263    /// Refers to the SCMP_CMP_MASKED_EQ operator (masked equal).
1264    ScmpCmpMaskedEq = 7,
1265}
1266
1267#[derive(
1268    Builder,
1269    Clone,
1270    CopyGetters,
1271    Debug,
1272    Default,
1273    Deserialize,
1274    Eq,
1275    Getters,
1276    Setters,
1277    PartialEq,
1278    Serialize,
1279)]
1280#[serde(rename_all = "camelCase")]
1281#[builder(
1282    default,
1283    pattern = "owned",
1284    setter(into, strip_option),
1285    build_fn(error = "OciSpecError")
1286)]
1287/// LinuxSyscall is used to match a syscall in seccomp.
1288pub struct LinuxSyscall {
1289    #[getset(get = "pub", set = "pub")]
1290    /// The names of the syscalls.
1291    names: Vec<String>,
1292
1293    #[getset(get_copy = "pub", set = "pub")]
1294    /// The action to be done for the syscalls.
1295    action: LinuxSeccompAction,
1296
1297    #[serde(default, skip_serializing_if = "Option::is_none")]
1298    #[getset(get_copy = "pub", set = "pub")]
1299    /// The error return value.
1300    errno_ret: Option<u32>,
1301
1302    #[serde(default, skip_serializing_if = "Option::is_none")]
1303    #[getset(get = "pub", set = "pub")]
1304    /// The arguments for the syscalls.
1305    args: Option<Vec<LinuxSeccompArg>>,
1306}
1307
1308#[derive(
1309    Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
1310)]
1311#[serde(rename_all = "camelCase")]
1312#[builder(
1313    default,
1314    pattern = "owned",
1315    setter(into, strip_option),
1316    build_fn(error = "OciSpecError")
1317)]
1318#[getset(get_copy = "pub", set = "pub")]
1319/// LinuxSeccompArg used for matching specific syscall arguments in seccomp.
1320pub struct LinuxSeccompArg {
1321    /// The index of the argument.
1322    index: usize,
1323
1324    /// The value of the argument.
1325    value: u64,
1326
1327    #[serde(default, skip_serializing_if = "Option::is_none")]
1328    /// The second value of the argument.
1329    value_two: Option<u64>,
1330
1331    /// The operator for the argument.
1332    op: LinuxSeccompOperator,
1333}
1334
1335/// Default masks paths, cannot read these host files.
1336pub fn get_default_maskedpaths() -> Vec<String> {
1337    vec![
1338        // For example now host interfaces such as
1339        // bluetooth cannot be accessed due to /proc/acpi
1340        "/proc/acpi".to_string(),
1341        "/proc/asound".to_string(),
1342        "/proc/kcore".to_string(),
1343        "/proc/keys".to_string(),
1344        "/proc/latency_stats".to_string(),
1345        "/proc/timer_list".to_string(),
1346        "/proc/timer_stats".to_string(),
1347        "/proc/sched_debug".to_string(),
1348        "/sys/firmware".to_string(),
1349        "/proc/scsi".to_string(),
1350    ]
1351}
1352
1353/// Default readonly paths, for example most containers shouldn't have permission to write to
1354/// `/proc/sys`.
1355pub fn get_default_readonly_paths() -> Vec<String> {
1356    vec![
1357        "/proc/bus".to_string(),
1358        "/proc/fs".to_string(),
1359        "/proc/irq".to_string(),
1360        "/proc/sys".to_string(),
1361        "/proc/sysrq-trigger".to_string(),
1362    ]
1363}
1364
1365#[derive(
1366    Builder,
1367    Clone,
1368    Debug,
1369    Default,
1370    Deserialize,
1371    Eq,
1372    Getters,
1373    MutGetters,
1374    Setters,
1375    PartialEq,
1376    Serialize,
1377)]
1378#[serde(rename_all = "camelCase")]
1379#[builder(
1380    default,
1381    pattern = "owned",
1382    setter(into, strip_option),
1383    build_fn(error = "OciSpecError")
1384)]
1385#[getset(get_mut = "pub", get = "pub", set = "pub")]
1386/// LinuxIntelRdt has container runtime resource constraints for Intel RDT CAT and MBA
1387/// features and flags enabling Intel RDT CMT and MBM features.
1388/// Intel RDT features are available in Linux 4.14 and newer kernel versions.
1389pub struct LinuxIntelRdt {
1390    #[serde(default, skip_serializing_if = "Option::is_none", rename = "closID")]
1391    /// The identity for RDT Class of Service.
1392    clos_id: Option<String>,
1393
1394    #[serde(default, skip_serializing_if = "Option::is_none")]
1395    /// The schema for L3 cache id and capacity bitmask (CBM).
1396    /// Format: "L3:&lt;cache_id0&gt;=&lt;cbm0&gt;;&lt;cache_id1&gt;=&lt;cbm1&gt;;..."
1397    l3_cache_schema: Option<String>,
1398
1399    #[serde(default, skip_serializing_if = "Option::is_none")]
1400    /// The schema of memory bandwidth per L3 cache id.
1401    /// Format: "MB:&lt;cache_id0&gt;=bandwidth0;&lt;cache_id1&gt;=bandwidth1;..."
1402    /// The unit of memory bandwidth is specified in "percentages" by
1403    /// default, and in "MBps" if MBA Software Controller is
1404    /// enabled.
1405    mem_bw_schema: Option<String>,
1406
1407    #[serde(default, skip_serializing_if = "Option::is_none")]
1408    /// EnableCMT is the flag to indicate if the Intel RDT CMT is enabled. CMT (Cache Monitoring Technology) supports monitoring of
1409    /// the last-level cache (LLC) occupancy for the container.
1410    enable_cmt: Option<bool>,
1411
1412    #[serde(default, skip_serializing_if = "Option::is_none")]
1413    /// EnableMBM is the flag to indicate if the Intel RDT MBM is enabled. MBM (Memory Bandwidth Monitoring) supports monitoring of
1414    /// total and local memory bandwidth for the container.
1415    enable_mbm: Option<bool>,
1416}
1417
1418#[derive(
1419    Builder,
1420    Clone,
1421    CopyGetters,
1422    Debug,
1423    Default,
1424    Deserialize,
1425    Eq,
1426    Getters,
1427    Setters,
1428    PartialEq,
1429    Serialize,
1430)]
1431#[builder(
1432    default,
1433    pattern = "owned",
1434    setter(into, strip_option),
1435    build_fn(error = "OciSpecError")
1436)]
1437/// LinuxPersonality represents the Linux personality syscall input.
1438pub struct LinuxPersonality {
1439    #[getset(get_copy = "pub", set = "pub")]
1440    /// Domain for the personality.
1441    domain: LinuxPersonalityDomain,
1442
1443    #[serde(default, skip_serializing_if = "Option::is_none")]
1444    #[getset(get = "pub", set = "pub")]
1445    /// Additional flags
1446    flags: Option<Vec<String>>,
1447}
1448
1449#[derive(
1450    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1451)]
1452/// Define domain and flags for LinuxPersonality.
1453pub enum LinuxPersonalityDomain {
1454    #[serde(rename = "LINUX")]
1455    #[strum(serialize = "LINUX")]
1456    /// PerLinux is the standard Linux personality.
1457    #[default]
1458    PerLinux,
1459
1460    #[serde(rename = "LINUX32")]
1461    #[strum(serialize = "LINUX32")]
1462    /// PerLinux32 sets personality to 32 bit.
1463    PerLinux32,
1464}
1465
1466#[derive(
1467    Builder,
1468    Clone,
1469    CopyGetters,
1470    Debug,
1471    Deserialize,
1472    Eq,
1473    Getters,
1474    MutGetters,
1475    Setters,
1476    PartialEq,
1477    Serialize,
1478)]
1479#[serde(rename_all = "camelCase")]
1480#[builder(
1481    pattern = "owned",
1482    setter(into, strip_option),
1483    build_fn(error = "OciSpecError")
1484)]
1485/// LinuxMemoryPolicy represents input for the set_mempolicy syscall.
1486pub struct LinuxMemoryPolicy {
1487    #[getset(get_copy = "pub", set = "pub")]
1488    /// Mode for the set_mempolicy syscall.
1489    mode: MemoryPolicyModeType,
1490
1491    #[serde(default, skip_serializing_if = "Option::is_none")]
1492    #[getset(get = "pub", set = "pub")]
1493    /// Nodes representing the nodemask for the set_mempolicy syscall in comma separated ranges format.
1494    /// Format: "&lt;node0&gt;-&lt;node1&gt;,&lt;node2&gt;,&lt;node3&gt;-&lt;node4&gt;,..."
1495    nodes: Option<String>,
1496
1497    #[serde(default, skip_serializing_if = "Option::is_none")]
1498    #[getset(get = "pub", get_mut = "pub", set = "pub")]
1499    /// Flags for the set_mempolicy syscall.
1500    flags: Option<Vec<MemoryPolicyFlagType>>,
1501}
1502
1503impl Default for LinuxMemoryPolicy {
1504    fn default() -> Self {
1505        Self {
1506            mode: MemoryPolicyModeType::MpolDefault,
1507            nodes: None,
1508            flags: None,
1509        }
1510    }
1511}
1512
1513#[derive(
1514    Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString,
1515)]
1516/// MemoryPolicyModeType defines the memory policy mode.
1517pub enum MemoryPolicyModeType {
1518    #[serde(rename = "MPOL_DEFAULT")]
1519    #[strum(serialize = "MPOL_DEFAULT")]
1520    /// MpolDefault - Default NUMA policy.
1521    #[default]
1522    MpolDefault,
1523
1524    #[serde(rename = "MPOL_BIND")]
1525    #[strum(serialize = "MPOL_BIND")]
1526    /// MpolBind - Bind memory allocation to specific nodes.
1527    MpolBind,
1528
1529    #[serde(rename = "MPOL_INTERLEAVE")]
1530    #[strum(serialize = "MPOL_INTERLEAVE")]
1531    /// MpolInterleave - Interleave memory allocation across nodes.
1532    MpolInterleave,
1533
1534    #[serde(rename = "MPOL_WEIGHTED_INTERLEAVE")]
1535    #[strum(serialize = "MPOL_WEIGHTED_INTERLEAVE")]
1536    /// MpolWeightedInterleave - Weighted interleave memory allocation across nodes.
1537    MpolWeightedInterleave,
1538
1539    #[serde(rename = "MPOL_PREFERRED")]
1540    #[strum(serialize = "MPOL_PREFERRED")]
1541    /// MpolPreferred - Prefer memory allocation from specific nodes.
1542    MpolPreferred,
1543
1544    #[serde(rename = "MPOL_PREFERRED_MANY")]
1545    #[strum(serialize = "MPOL_PREFERRED_MANY")]
1546    /// MpolPreferredMany - Prefer memory allocation from multiple nodes.
1547    MpolPreferredMany,
1548
1549    #[serde(rename = "MPOL_LOCAL")]
1550    #[strum(serialize = "MPOL_LOCAL")]
1551    /// MpolLocal - Local node memory allocation.
1552    MpolLocal,
1553}
1554
1555#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
1556/// MemoryPolicyFlagType defines the memory policy flags.
1557pub enum MemoryPolicyFlagType {
1558    #[serde(rename = "MPOL_F_NUMA_BALANCING")]
1559    #[strum(serialize = "MPOL_F_NUMA_BALANCING")]
1560    /// MpolFNumaBalancing - Enable NUMA balancing.
1561    MpolFNumaBalancing,
1562
1563    #[serde(rename = "MPOL_F_RELATIVE_NODES")]
1564    #[strum(serialize = "MPOL_F_RELATIVE_NODES")]
1565    /// MpolFRelativeNodes - Use relative node numbers.
1566    MpolFRelativeNodes,
1567
1568    #[serde(rename = "MPOL_F_STATIC_NODES")]
1569    #[strum(serialize = "MPOL_F_STATIC_NODES")]
1570    /// MpolFStaticNodes - Use static node numbers.
1571    MpolFStaticNodes,
1572}
1573
1574#[derive(
1575    Builder,
1576    Clone,
1577    CopyGetters,
1578    Debug,
1579    Default,
1580    Deserialize,
1581    Eq,
1582    Getters,
1583    Setters,
1584    PartialEq,
1585    Serialize,
1586)]
1587#[builder(
1588    default,
1589    pattern = "owned",
1590    setter(into, strip_option),
1591    build_fn(error = "OciSpecError")
1592)]
1593/// LinuxTimeOffset specifies the offset for Time Namespace
1594pub struct LinuxTimeOffset {
1595    /// Secs is the offset of clock (in secs) in the container
1596    #[serde(default, skip_serializing_if = "Option::is_none")]
1597    #[getset(get_copy = "pub", set = "pub")]
1598    secs: Option<i64>,
1599    /// Nanosecs is the additional offset for Secs (in nanosecs)
1600    #[serde(default, skip_serializing_if = "Option::is_none")]
1601    #[getset(get_copy = "pub", set = "pub")]
1602    nanosecs: Option<u32>,
1603}
1604
1605#[cfg(feature = "proptests")]
1606use quickcheck::{Arbitrary, Gen};
1607
1608#[cfg(feature = "proptests")]
1609fn some_none_generator_util<T: Arbitrary>(g: &mut Gen) -> Option<T> {
1610    let choice = g.choose(&[true, false]).unwrap();
1611    match choice {
1612        false => None,
1613        true => Some(T::arbitrary(g)),
1614    }
1615}
1616
1617#[cfg(feature = "proptests")]
1618impl Arbitrary for LinuxDeviceCgroup {
1619    fn arbitrary(g: &mut Gen) -> LinuxDeviceCgroup {
1620        let typ_choices = ["a", "b", "c", "u", "p"];
1621
1622        let typ_chosen = g.choose(&typ_choices).unwrap();
1623
1624        let typ = match typ_chosen.to_string().as_str() {
1625            "a" => LinuxDeviceType::A,
1626            "b" => LinuxDeviceType::B,
1627            "c" => LinuxDeviceType::C,
1628            "u" => LinuxDeviceType::U,
1629            "p" => LinuxDeviceType::P,
1630            _ => LinuxDeviceType::A,
1631        };
1632
1633        let access_choices = ["rwm", "m"];
1634        LinuxDeviceCgroup {
1635            allow: bool::arbitrary(g),
1636            typ: typ.into(),
1637            major: some_none_generator_util::<i64>(g),
1638            minor: some_none_generator_util::<i64>(g),
1639            access: g.choose(&access_choices).unwrap().to_string().into(),
1640        }
1641    }
1642}
1643
1644#[cfg(feature = "proptests")]
1645impl Arbitrary for LinuxMemory {
1646    fn arbitrary(g: &mut Gen) -> LinuxMemory {
1647        LinuxMemory {
1648            kernel: some_none_generator_util::<i64>(g),
1649            kernel_tcp: some_none_generator_util::<i64>(g),
1650            limit: some_none_generator_util::<i64>(g),
1651            reservation: some_none_generator_util::<i64>(g),
1652            swap: some_none_generator_util::<i64>(g),
1653            swappiness: some_none_generator_util::<u64>(g),
1654            disable_oom_killer: some_none_generator_util::<bool>(g),
1655            use_hierarchy: some_none_generator_util::<bool>(g),
1656            check_before_update: some_none_generator_util::<bool>(g),
1657        }
1658    }
1659}
1660
1661#[cfg(feature = "proptests")]
1662impl Arbitrary for LinuxHugepageLimit {
1663    fn arbitrary(g: &mut Gen) -> LinuxHugepageLimit {
1664        let unit_choice = ["KB", "MB", "GB"];
1665        let unit = g.choose(&unit_choice).unwrap();
1666        let page_size = u64::arbitrary(g).to_string() + unit;
1667
1668        LinuxHugepageLimit {
1669            page_size,
1670            limit: i64::arbitrary(g),
1671        }
1672    }
1673}
1674
1675#[cfg(test)]
1676mod tests {
1677    use super::*;
1678
1679    // LinuxDeviceType test cases
1680    #[test]
1681    fn device_type_enum_to_str() {
1682        let type_a = LinuxDeviceType::A;
1683        assert_eq!(type_a.as_str(), "a");
1684
1685        let type_b = LinuxDeviceType::B;
1686        assert_eq!(type_b.as_str(), "b");
1687
1688        let type_c = LinuxDeviceType::C;
1689        assert_eq!(type_c.as_str(), "c");
1690    }
1691
1692    #[test]
1693    fn device_type_string_to_enum() {
1694        let devtype_str = "a";
1695        let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
1696        assert_eq!(devtype_enum, LinuxDeviceType::A);
1697
1698        let devtype_str = "b";
1699        let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
1700        assert_eq!(devtype_enum, LinuxDeviceType::B);
1701
1702        let devtype_str = "c";
1703        let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
1704        assert_eq!(devtype_enum, LinuxDeviceType::C);
1705
1706        let invalid_devtype_str = "x";
1707        let unknown_devtype = invalid_devtype_str.parse::<LinuxDeviceType>();
1708        assert!(unknown_devtype.is_err());
1709    }
1710
1711    // LinuxNamespaceType test cases
1712    #[test]
1713    fn ns_type_enum_to_string() {
1714        let type_a = LinuxNamespaceType::Network;
1715        assert_eq!(type_a.to_string(), "net");
1716
1717        let type_b = LinuxNamespaceType::Mount;
1718        assert_eq!(type_b.to_string(), "mnt");
1719
1720        let type_c = LinuxNamespaceType::Ipc;
1721        assert_eq!(type_c.to_string(), "ipc");
1722    }
1723
1724    #[test]
1725    fn ns_type_string_to_enum() {
1726        let nstype_str = "net";
1727        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1728        assert_eq!(nstype_enum, LinuxNamespaceType::Network);
1729
1730        let nstype_str = "network";
1731        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1732        assert_eq!(nstype_enum, LinuxNamespaceType::Network);
1733
1734        let nstype_str = "ipc";
1735        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1736        assert_eq!(nstype_enum, LinuxNamespaceType::Ipc);
1737
1738        let nstype_str = "cgroup";
1739        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1740        assert_eq!(nstype_enum, LinuxNamespaceType::Cgroup);
1741
1742        let nstype_str = "mount";
1743        let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
1744        assert_eq!(nstype_enum, LinuxNamespaceType::Mount);
1745
1746        let invalid_nstype_str = "xxx";
1747        let unknown_nstype = LinuxNamespaceType::try_from(invalid_nstype_str);
1748        assert!(unknown_nstype.is_err());
1749    }
1750
1751    // LinuxSeccompAction test cases
1752    #[test]
1753    fn seccomp_action_enum_to_string() {
1754        let type_a = LinuxSeccompAction::ScmpActKill;
1755        assert_eq!(type_a.to_string(), "SCMP_ACT_KILL");
1756
1757        let type_b = LinuxSeccompAction::ScmpActAllow;
1758        assert_eq!(type_b.to_string(), "SCMP_ACT_ALLOW");
1759
1760        let type_c = LinuxSeccompAction::ScmpActNotify;
1761        assert_eq!(type_c.to_string(), "SCMP_ACT_NOTIFY");
1762    }
1763
1764    #[test]
1765    fn seccomp_action_string_to_enum() {
1766        let action_str = "SCMP_ACT_KILL";
1767        let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
1768        assert_eq!(action_enum, LinuxSeccompAction::ScmpActKill);
1769
1770        let action_str = "SCMP_ACT_ALLOW";
1771        let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
1772        assert_eq!(action_enum, LinuxSeccompAction::ScmpActAllow);
1773
1774        let action_str = "SCMP_ACT_NOTIFY";
1775        let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
1776        assert_eq!(action_enum, LinuxSeccompAction::ScmpActNotify);
1777
1778        let invalid_action_str = "x";
1779        let unknown_action = invalid_action_str.parse::<LinuxSeccompAction>();
1780        assert!(unknown_action.is_err());
1781    }
1782
1783    // LinuxSeccomp Arch test cases
1784    #[test]
1785    fn seccomp_arch_enum_to_string() {
1786        let type_a = Arch::ScmpArchX86_64;
1787        assert_eq!(type_a.to_string(), "SCMP_ARCH_X86_64");
1788
1789        let type_b = Arch::ScmpArchAarch64;
1790        assert_eq!(type_b.to_string(), "SCMP_ARCH_AARCH64");
1791
1792        let type_c = Arch::ScmpArchPpc64le;
1793        assert_eq!(type_c.to_string(), "SCMP_ARCH_PPC64LE");
1794    }
1795
1796    #[test]
1797    fn seccomp_arch_string_to_enum() {
1798        let arch_type_str = "SCMP_ARCH_X86_64";
1799        let arch_type_enum: Arch = arch_type_str.parse().unwrap();
1800        assert_eq!(arch_type_enum, Arch::ScmpArchX86_64);
1801
1802        let arch_type_str = "SCMP_ARCH_AARCH64";
1803        let arch_type_enum: Arch = arch_type_str.parse().unwrap();
1804        assert_eq!(arch_type_enum, Arch::ScmpArchAarch64);
1805
1806        let arch_type_str = "SCMP_ARCH_PPC64LE";
1807        let arch_type_enum: Arch = arch_type_str.parse().unwrap();
1808        assert_eq!(arch_type_enum, Arch::ScmpArchPpc64le);
1809
1810        let invalid_arch_str = "x";
1811        let unknown_arch = invalid_arch_str.parse::<Arch>();
1812        assert!(unknown_arch.is_err());
1813    }
1814
1815    // LinuxSeccompFilterFlag test cases
1816    #[test]
1817    fn seccomp_filter_flag_enum_to_string() {
1818        let type_a = LinuxSeccompFilterFlag::SeccompFilterFlagLog;
1819        assert_eq!(type_a.to_string(), "SECCOMP_FILTER_FLAG_LOG");
1820
1821        let type_b = LinuxSeccompFilterFlag::SeccompFilterFlagTsync;
1822        assert_eq!(type_b.to_string(), "SECCOMP_FILTER_FLAG_TSYNC");
1823
1824        let type_c = LinuxSeccompFilterFlag::SeccompFilterFlagSpecAllow;
1825        assert_eq!(type_c.to_string(), "SECCOMP_FILTER_FLAG_SPEC_ALLOW");
1826    }
1827
1828    #[test]
1829    fn seccomp_filter_flag_string_to_enum() {
1830        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_LOG";
1831        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1832        assert_eq!(
1833            filter_flag_type_enum,
1834            LinuxSeccompFilterFlag::SeccompFilterFlagLog
1835        );
1836
1837        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_TSYNC";
1838        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1839        assert_eq!(
1840            filter_flag_type_enum,
1841            LinuxSeccompFilterFlag::SeccompFilterFlagTsync
1842        );
1843
1844        let filter_flag_type_str = "SECCOMP_FILTER_FLAG_SPEC_ALLOW";
1845        let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
1846        assert_eq!(
1847            filter_flag_type_enum,
1848            LinuxSeccompFilterFlag::SeccompFilterFlagSpecAllow
1849        );
1850
1851        let invalid_filter_flag_str = "x";
1852        let unknown_arch = invalid_filter_flag_str.parse::<LinuxSeccompFilterFlag>();
1853        assert!(unknown_arch.is_err());
1854    }
1855
1856    // LinuxSeccompOperator test cases
1857    #[test]
1858    fn seccomp_operator_enum_to_string() {
1859        let type_a = LinuxSeccompOperator::ScmpCmpNe;
1860        assert_eq!(type_a.to_string(), "SCMP_CMP_NE");
1861
1862        let type_b = LinuxSeccompOperator::ScmpCmpMaskedEq;
1863        assert_eq!(type_b.to_string(), "SCMP_CMP_MASKED_EQ");
1864
1865        let type_c = LinuxSeccompOperator::ScmpCmpGt;
1866        assert_eq!(type_c.to_string(), "SCMP_CMP_GT");
1867    }
1868
1869    #[test]
1870    fn seccomp_operator_string_to_enum() {
1871        let seccomp_operator_str = "SCMP_CMP_GT";
1872        let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
1873        assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpGt);
1874
1875        let seccomp_operator_str = "SCMP_CMP_NE";
1876        let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
1877        assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpNe);
1878
1879        let seccomp_operator_str = "SCMP_CMP_MASKED_EQ";
1880        let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
1881        assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpMaskedEq);
1882
1883        let invalid_seccomp_operator_str = "x";
1884        let unknown_operator = invalid_seccomp_operator_str.parse::<LinuxSeccompOperator>();
1885        assert!(unknown_operator.is_err());
1886    }
1887
1888    // MemoryPolicyModeType test cases
1889    #[test]
1890    fn memory_policy_mode_enum_to_string() {
1891        let mode_a = MemoryPolicyModeType::MpolDefault;
1892        assert_eq!(mode_a.to_string(), "MPOL_DEFAULT");
1893
1894        let mode_b = MemoryPolicyModeType::MpolBind;
1895        assert_eq!(mode_b.to_string(), "MPOL_BIND");
1896
1897        let mode_c = MemoryPolicyModeType::MpolInterleave;
1898        assert_eq!(mode_c.to_string(), "MPOL_INTERLEAVE");
1899
1900        let mode_d = MemoryPolicyModeType::MpolWeightedInterleave;
1901        assert_eq!(mode_d.to_string(), "MPOL_WEIGHTED_INTERLEAVE");
1902
1903        let mode_e = MemoryPolicyModeType::MpolPreferred;
1904        assert_eq!(mode_e.to_string(), "MPOL_PREFERRED");
1905
1906        let mode_f = MemoryPolicyModeType::MpolPreferredMany;
1907        assert_eq!(mode_f.to_string(), "MPOL_PREFERRED_MANY");
1908
1909        let mode_g = MemoryPolicyModeType::MpolLocal;
1910        assert_eq!(mode_g.to_string(), "MPOL_LOCAL");
1911    }
1912
1913    #[test]
1914    fn memory_policy_mode_string_to_enum() {
1915        let mode_str = "MPOL_INTERLEAVE";
1916        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1917        assert_eq!(mode_enum, MemoryPolicyModeType::MpolInterleave);
1918
1919        let mode_str = "MPOL_BIND";
1920        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1921        assert_eq!(mode_enum, MemoryPolicyModeType::MpolBind);
1922
1923        let mode_str = "MPOL_DEFAULT";
1924        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1925        assert_eq!(mode_enum, MemoryPolicyModeType::MpolDefault);
1926
1927        let mode_str = "MPOL_WEIGHTED_INTERLEAVE";
1928        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1929        assert_eq!(mode_enum, MemoryPolicyModeType::MpolWeightedInterleave);
1930
1931        let mode_str = "MPOL_PREFERRED";
1932        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1933        assert_eq!(mode_enum, MemoryPolicyModeType::MpolPreferred);
1934
1935        let mode_str = "MPOL_PREFERRED_MANY";
1936        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1937        assert_eq!(mode_enum, MemoryPolicyModeType::MpolPreferredMany);
1938
1939        let mode_str = "MPOL_LOCAL";
1940        let mode_enum: MemoryPolicyModeType = mode_str.parse().unwrap();
1941        assert_eq!(mode_enum, MemoryPolicyModeType::MpolLocal);
1942
1943        let invalid_mode_str = "INVALID_MODE";
1944        let unknown_mode = invalid_mode_str.parse::<MemoryPolicyModeType>();
1945        assert!(unknown_mode.is_err());
1946    }
1947
1948    // MemoryPolicyFlagType test cases
1949    #[test]
1950    fn memory_policy_flag_enum_to_string() {
1951        let flag_a = MemoryPolicyFlagType::MpolFNumaBalancing;
1952        assert_eq!(flag_a.to_string(), "MPOL_F_NUMA_BALANCING");
1953
1954        let flag_b = MemoryPolicyFlagType::MpolFRelativeNodes;
1955        assert_eq!(flag_b.to_string(), "MPOL_F_RELATIVE_NODES");
1956
1957        let flag_c = MemoryPolicyFlagType::MpolFStaticNodes;
1958        assert_eq!(flag_c.to_string(), "MPOL_F_STATIC_NODES");
1959    }
1960
1961    #[test]
1962    fn memory_policy_flag_string_to_enum() {
1963        let flag_str = "MPOL_F_NUMA_BALANCING";
1964        let flag_enum: MemoryPolicyFlagType = flag_str.parse().unwrap();
1965        assert_eq!(flag_enum, MemoryPolicyFlagType::MpolFNumaBalancing);
1966
1967        let flag_str = "MPOL_F_RELATIVE_NODES";
1968        let flag_enum: MemoryPolicyFlagType = flag_str.parse().unwrap();
1969        assert_eq!(flag_enum, MemoryPolicyFlagType::MpolFRelativeNodes);
1970
1971        let flag_str = "MPOL_F_STATIC_NODES";
1972        let flag_enum: MemoryPolicyFlagType = flag_str.parse().unwrap();
1973        assert_eq!(flag_enum, MemoryPolicyFlagType::MpolFStaticNodes);
1974
1975        let invalid_flag_str = "INVALID_FLAG";
1976        let unknown_flag = invalid_flag_str.parse::<MemoryPolicyFlagType>();
1977        assert!(unknown_flag.is_err());
1978    }
1979
1980    #[test]
1981    fn test_linux_memory_policy_serialization() {
1982        let memory_policy = LinuxMemoryPolicy {
1983            mode: MemoryPolicyModeType::MpolInterleave,
1984            nodes: Some("0-3,7".to_string()),
1985            flags: Some(vec![
1986                MemoryPolicyFlagType::MpolFStaticNodes,
1987                MemoryPolicyFlagType::MpolFRelativeNodes,
1988            ]),
1989        };
1990
1991        let json = serde_json::to_string(&memory_policy).unwrap();
1992        let deserialized: LinuxMemoryPolicy = serde_json::from_str(&json).unwrap();
1993
1994        assert_eq!(deserialized.mode, MemoryPolicyModeType::MpolInterleave);
1995        assert_eq!(deserialized.nodes, Some("0-3,7".to_string()));
1996        assert_eq!(
1997            deserialized.flags,
1998            Some(vec![
1999                MemoryPolicyFlagType::MpolFStaticNodes,
2000                MemoryPolicyFlagType::MpolFRelativeNodes,
2001            ])
2002        );
2003    }
2004
2005    #[test]
2006    fn test_linux_memory_policy_default() {
2007        let memory_policy = LinuxMemoryPolicy::default();
2008        assert_eq!(memory_policy.mode, MemoryPolicyModeType::MpolDefault);
2009        assert_eq!(memory_policy.nodes, None);
2010        assert_eq!(memory_policy.flags, None);
2011    }
2012}