vmm/vmm_config/
entropy.rs

1// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::ops::Deref;
5use std::sync::{Arc, Mutex};
6
7use serde::{Deserialize, Serialize};
8
9use super::RateLimiterConfig;
10use crate::devices::virtio::rng::{Entropy, EntropyError};
11
12/// This struct represents the strongly typed equivalent of the json body from entropy device
13/// related requests.
14#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
15#[serde(deny_unknown_fields)]
16pub struct EntropyDeviceConfig {
17    /// Configuration for RateLimiter of Entropy device
18    pub rate_limiter: Option<RateLimiterConfig>,
19}
20
21impl From<&Entropy> for EntropyDeviceConfig {
22    fn from(dev: &Entropy) -> Self {
23        let rate_limiter: RateLimiterConfig = dev.rate_limiter().into();
24        EntropyDeviceConfig {
25            rate_limiter: rate_limiter.into_option(),
26        }
27    }
28}
29
30/// Errors that can occur while handling configuration for
31/// an entropy device
32#[derive(Debug, thiserror::Error, displaydoc::Display)]
33pub enum EntropyDeviceError {
34    /// Could not create Entropy device: {0}
35    CreateDevice(#[from] EntropyError),
36    /// Could not create RateLimiter from configuration: {0}
37    CreateRateLimiter(#[from] std::io::Error),
38}
39
40/// A builder type used to construct an Entropy device
41#[derive(Debug, Default)]
42pub struct EntropyDeviceBuilder(Option<Arc<Mutex<Entropy>>>);
43
44impl EntropyDeviceBuilder {
45    /// Create a new instance for the builder
46    pub fn new() -> Self {
47        Self(None)
48    }
49
50    /// Build an entropy device and return a (counted) reference to it protected by a mutex
51    pub fn build(
52        &mut self,
53        config: EntropyDeviceConfig,
54    ) -> Result<Arc<Mutex<Entropy>>, EntropyDeviceError> {
55        let rate_limiter = config
56            .rate_limiter
57            .map(RateLimiterConfig::try_into)
58            .transpose()?;
59        let dev = Arc::new(Mutex::new(Entropy::new(rate_limiter.unwrap_or_default())?));
60        self.0 = Some(dev.clone());
61
62        Ok(dev)
63    }
64
65    /// Insert a new entropy device from a configuration object
66    pub fn insert(&mut self, config: EntropyDeviceConfig) -> Result<(), EntropyDeviceError> {
67        let _ = self.build(config)?;
68        Ok(())
69    }
70
71    /// Get a reference to the entropy device, if present
72    pub fn get(&self) -> Option<&Arc<Mutex<Entropy>>> {
73        self.0.as_ref()
74    }
75
76    /// Get the configuration of the entropy device (if any)
77    pub fn config(&self) -> Option<EntropyDeviceConfig> {
78        self.0
79            .as_ref()
80            .map(|dev| EntropyDeviceConfig::from(dev.lock().unwrap().deref()))
81    }
82
83    /// Set the entropy device from an already created object
84    pub fn set_device(&mut self, device: Arc<Mutex<Entropy>>) {
85        self.0 = Some(device);
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::rate_limiter::RateLimiter;
93
94    #[test]
95    fn test_entropy_device_create() {
96        let config = EntropyDeviceConfig::default();
97        let mut builder = EntropyDeviceBuilder::new();
98        assert!(builder.get().is_none());
99
100        builder.insert(config.clone()).unwrap();
101        assert!(builder.get().is_some());
102        assert_eq!(builder.config().unwrap(), config);
103    }
104
105    #[test]
106    fn test_set_device() {
107        let mut builder = EntropyDeviceBuilder::new();
108        let device = Entropy::new(RateLimiter::default()).unwrap();
109        assert!(builder.0.is_none());
110        builder.set_device(Arc::new(Mutex::new(device)));
111        assert!(builder.0.is_some());
112    }
113}