Skip to main content

oci_spec/runtime/
linux.rs

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