vmm/devices/virtio/rng/
device.rs

1// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::io;
5use std::ops::Deref;
6use std::sync::Arc;
7
8use aws_lc_rs::rand;
9use log::info;
10use vm_memory::GuestMemoryError;
11use vmm_sys_util::eventfd::EventFd;
12
13use super::metrics::METRICS;
14use super::{RNG_NUM_QUEUES, RNG_QUEUE};
15use crate::devices::DeviceError;
16use crate::devices::virtio::ActivateError;
17use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice};
18use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1;
19use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_RNG;
20use crate::devices::virtio::iov_deque::IovDequeError;
21use crate::devices::virtio::iovec::IoVecBufferMut;
22use crate::devices::virtio::queue::{FIRECRACKER_MAX_QUEUE_SIZE, InvalidAvailIdx, Queue};
23use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType};
24use crate::impl_device_type;
25use crate::logger::{IncMetric, debug, error};
26use crate::rate_limiter::{RateLimiter, TokenType};
27use crate::vstate::memory::GuestMemoryMmap;
28
29pub const ENTROPY_DEV_ID: &str = "rng";
30
31#[derive(Debug, thiserror::Error, displaydoc::Display)]
32pub enum EntropyError {
33    /// Error while handling an Event file descriptor: {0}
34    EventFd(#[from] io::Error),
35    /// Bad guest memory buffer: {0}
36    GuestMemory(#[from] GuestMemoryError),
37    /// Could not get random bytes: {0}
38    Random(#[from] aws_lc_rs::error::Unspecified),
39    /// Underlying IovDeque error: {0}
40    IovDeque(#[from] IovDequeError),
41}
42
43#[derive(Debug)]
44pub struct Entropy {
45    // VirtIO fields
46    avail_features: u64,
47    acked_features: u64,
48    activate_event: EventFd,
49
50    // Transport fields
51    device_state: DeviceState,
52    pub(crate) queues: Vec<Queue>,
53    queue_events: Vec<EventFd>,
54
55    // Device specific fields
56    rate_limiter: RateLimiter,
57
58    buffer: IoVecBufferMut,
59}
60
61impl Entropy {
62    pub fn new(rate_limiter: RateLimiter) -> Result<Self, EntropyError> {
63        let queues = vec![Queue::new(FIRECRACKER_MAX_QUEUE_SIZE); RNG_NUM_QUEUES];
64        Self::new_with_queues(queues, rate_limiter)
65    }
66
67    pub fn new_with_queues(
68        queues: Vec<Queue>,
69        rate_limiter: RateLimiter,
70    ) -> Result<Self, EntropyError> {
71        let activate_event = EventFd::new(libc::EFD_NONBLOCK)?;
72        let queue_events = (0..RNG_NUM_QUEUES)
73            .map(|_| EventFd::new(libc::EFD_NONBLOCK))
74            .collect::<Result<Vec<EventFd>, io::Error>>()?;
75
76        Ok(Self {
77            avail_features: 1 << VIRTIO_F_VERSION_1,
78            acked_features: 0u64,
79            activate_event,
80            device_state: DeviceState::Inactive,
81            queues,
82            queue_events,
83            rate_limiter,
84            buffer: IoVecBufferMut::new()?,
85        })
86    }
87
88    pub fn id(&self) -> &str {
89        ENTROPY_DEV_ID
90    }
91
92    fn signal_used_queue(&self) -> Result<(), DeviceError> {
93        self.interrupt_trigger()
94            .trigger(VirtioInterruptType::Queue(RNG_QUEUE.try_into().unwrap()))
95            .map_err(DeviceError::FailedSignalingIrq)
96    }
97
98    fn rate_limit_request(&mut self, bytes: u64) -> bool {
99        if !self.rate_limiter.consume(1, TokenType::Ops) {
100            return false;
101        }
102
103        if !self.rate_limiter.consume(bytes, TokenType::Bytes) {
104            self.rate_limiter.manual_replenish(1, TokenType::Ops);
105            return false;
106        }
107
108        true
109    }
110
111    fn rate_limit_replenish_request(rate_limiter: &mut RateLimiter, bytes: u64) {
112        rate_limiter.manual_replenish(1, TokenType::Ops);
113        rate_limiter.manual_replenish(bytes, TokenType::Bytes);
114    }
115
116    fn handle_one(&mut self) -> Result<u32, EntropyError> {
117        // If guest provided us with an empty buffer just return directly
118        if self.buffer.is_empty() {
119            return Ok(0);
120        }
121
122        let mut rand_bytes = vec![0; self.buffer.len() as usize];
123        rand::fill(&mut rand_bytes).inspect_err(|_| {
124            METRICS.host_rng_fails.inc();
125        })?;
126
127        // It is ok to unwrap here. We are writing `iovec.len()` bytes at offset 0.
128        self.buffer.write_all_volatile_at(&rand_bytes, 0).unwrap();
129        Ok(self.buffer.len())
130    }
131
132    fn process_entropy_queue(&mut self) -> Result<(), InvalidAvailIdx> {
133        let mut used_any = false;
134        while let Some(desc) = self.queues[RNG_QUEUE].pop()? {
135            // This is safe since we checked in the event handler that the device is activated.
136            let mem = &self.device_state.active_state().unwrap().mem;
137            let index = desc.index;
138            METRICS.entropy_event_count.inc();
139
140            // SAFETY: This descriptor chain points to a single `DescriptorChain` memory buffer,
141            // no other `IoVecBufferMut` object points to the same `DescriptorChain` at the same
142            // time and we clear the `iovec` after we process the request.
143            let bytes = match unsafe { self.buffer.load_descriptor_chain(mem, desc) } {
144                Ok(()) => {
145                    debug!(
146                        "entropy: guest request for {} bytes of entropy",
147                        self.buffer.len()
148                    );
149
150                    // Check for available rate limiting budget.
151                    // If not enough budget is available, leave the request descriptor in the queue
152                    // to handle once we do have budget.
153                    if !self.rate_limit_request(u64::from(self.buffer.len())) {
154                        debug!("entropy: throttling entropy queue");
155                        METRICS.entropy_rate_limiter_throttled.inc();
156                        self.queues[RNG_QUEUE].undo_pop();
157                        break;
158                    }
159
160                    self.handle_one().unwrap_or_else(|err| {
161                        error!("entropy: {err}");
162                        METRICS.entropy_event_fails.inc();
163                        0
164                    })
165                }
166                Err(err) => {
167                    error!("entropy: Could not parse descriptor chain: {err}");
168                    METRICS.entropy_event_fails.inc();
169                    0
170                }
171            };
172
173            match self.queues[RNG_QUEUE].add_used(index, bytes) {
174                Ok(_) => {
175                    used_any = true;
176                    METRICS.entropy_bytes.add(bytes.into());
177                }
178                Err(err) => {
179                    error!("entropy: Could not add used descriptor to queue: {err}");
180                    Self::rate_limit_replenish_request(&mut self.rate_limiter, bytes.into());
181                    METRICS.entropy_event_fails.inc();
182                    // If we are not able to add a buffer to the used queue, something
183                    // is probably seriously wrong, so just stop processing additional
184                    // buffers
185                    break;
186                }
187            }
188        }
189        self.queues[RNG_QUEUE].advance_used_ring_idx();
190
191        if used_any {
192            self.signal_used_queue().unwrap_or_else(|err| {
193                error!("entropy: {err:?}");
194                METRICS.entropy_event_fails.inc()
195            });
196        }
197
198        Ok(())
199    }
200
201    pub(crate) fn process_entropy_queue_event(&mut self) {
202        if let Err(err) = self.queue_events[RNG_QUEUE].read() {
203            error!("Failed to read entropy queue event: {err}");
204            METRICS.entropy_event_fails.inc();
205        } else if !self.rate_limiter.is_blocked() {
206            // We are not throttled, handle the entropy queue
207            self.process_entropy_queue().unwrap()
208        } else {
209            METRICS.rate_limiter_event_count.inc();
210        }
211    }
212
213    pub(crate) fn process_rate_limiter_event(&mut self) {
214        METRICS.rate_limiter_event_count.inc();
215        match self.rate_limiter.event_handler() {
216            Ok(_) => {
217                // There might be enough budget now to process entropy requests.
218                self.process_entropy_queue().unwrap()
219            }
220            Err(err) => {
221                error!("entropy: Failed to handle rate-limiter event: {err:?}");
222                METRICS.entropy_event_fails.inc();
223            }
224        }
225    }
226
227    pub fn process_virtio_queues(&mut self) -> Result<(), InvalidAvailIdx> {
228        self.process_entropy_queue()
229    }
230
231    pub fn rate_limiter(&self) -> &RateLimiter {
232        &self.rate_limiter
233    }
234
235    pub(crate) fn set_avail_features(&mut self, features: u64) {
236        self.avail_features = features;
237    }
238
239    pub(crate) fn set_acked_features(&mut self, features: u64) {
240        self.acked_features = features;
241    }
242
243    pub(crate) fn set_activated(
244        &mut self,
245        mem: GuestMemoryMmap,
246        interrupt: Arc<dyn VirtioInterrupt>,
247    ) {
248        self.device_state = DeviceState::Activated(ActiveState { mem, interrupt });
249    }
250
251    pub(crate) fn activate_event(&self) -> &EventFd {
252        &self.activate_event
253    }
254}
255
256impl VirtioDevice for Entropy {
257    impl_device_type!(VIRTIO_ID_RNG);
258
259    fn queues(&self) -> &[Queue] {
260        &self.queues
261    }
262
263    fn queues_mut(&mut self) -> &mut [Queue] {
264        &mut self.queues
265    }
266
267    fn queue_events(&self) -> &[EventFd] {
268        &self.queue_events
269    }
270
271    fn interrupt_trigger(&self) -> &dyn VirtioInterrupt {
272        self.device_state
273            .active_state()
274            .expect("Device is not initialized")
275            .interrupt
276            .deref()
277    }
278
279    fn avail_features(&self) -> u64 {
280        self.avail_features
281    }
282
283    fn acked_features(&self) -> u64 {
284        self.acked_features
285    }
286
287    fn set_acked_features(&mut self, acked_features: u64) {
288        self.acked_features = acked_features;
289    }
290
291    fn read_config(&self, _offset: u64, mut _data: &mut [u8]) {}
292
293    fn write_config(&mut self, _offset: u64, _data: &[u8]) {}
294
295    fn is_activated(&self) -> bool {
296        self.device_state.is_activated()
297    }
298
299    fn activate(
300        &mut self,
301        mem: GuestMemoryMmap,
302        interrupt: Arc<dyn VirtioInterrupt>,
303    ) -> Result<(), ActivateError> {
304        for q in self.queues.iter_mut() {
305            q.initialize(&mem)
306                .map_err(ActivateError::QueueMemoryError)?;
307        }
308
309        self.activate_event.write(1).map_err(|_| {
310            METRICS.activate_fails.inc();
311            ActivateError::EventFd
312        })?;
313        self.device_state = DeviceState::Activated(ActiveState { mem, interrupt });
314        Ok(())
315    }
316
317    fn kick(&mut self) {
318        if self.is_activated() {
319            info!("kick entropy {}.", self.id());
320            self.process_virtio_queues();
321        }
322    }
323}
324
325#[cfg(test)]
326mod tests {
327    use std::time::Duration;
328
329    use super::*;
330    use crate::check_metric_after_block;
331    use crate::devices::virtio::device::VirtioDevice;
332    use crate::devices::virtio::queue::VIRTQ_DESC_F_WRITE;
333    use crate::devices::virtio::test_utils::test::{
334        VirtioTestDevice, VirtioTestHelper, create_virtio_mem,
335    };
336
337    impl VirtioTestDevice for Entropy {
338        fn set_queues(&mut self, queues: Vec<Queue>) {
339            self.queues = queues;
340        }
341
342        fn num_queues(&self) -> usize {
343            RNG_NUM_QUEUES
344        }
345    }
346
347    fn default_entropy() -> Entropy {
348        Entropy::new(RateLimiter::default()).unwrap()
349    }
350
351    #[test]
352    fn test_new() {
353        let entropy_dev = default_entropy();
354
355        assert_eq!(entropy_dev.avail_features(), 1 << VIRTIO_F_VERSION_1);
356        assert_eq!(entropy_dev.acked_features(), 0);
357        assert!(!entropy_dev.is_activated());
358    }
359
360    #[test]
361    fn test_id() {
362        let entropy_dev = default_entropy();
363        assert_eq!(entropy_dev.id(), ENTROPY_DEV_ID);
364    }
365
366    #[test]
367    fn test_device_type() {
368        let entropy_dev = default_entropy();
369        assert_eq!(entropy_dev.device_type(), VIRTIO_ID_RNG);
370    }
371
372    #[test]
373    fn test_read_config() {
374        let entropy_dev = default_entropy();
375        let mut config = vec![0; 10];
376
377        entropy_dev.read_config(0, &mut config);
378        assert_eq!(config, vec![0; 10]);
379
380        entropy_dev.read_config(1, &mut config);
381        assert_eq!(config, vec![0; 10]);
382
383        entropy_dev.read_config(2, &mut config);
384        assert_eq!(config, vec![0; 10]);
385
386        entropy_dev.read_config(1024, &mut config);
387        assert_eq!(config, vec![0; 10]);
388    }
389
390    #[test]
391    fn test_write_config() {
392        let mut entropy_dev = default_entropy();
393        let mut read_config = vec![0; 10];
394        let write_config = vec![42; 10];
395
396        entropy_dev.write_config(0, &write_config);
397        entropy_dev.read_config(0, &mut read_config);
398        assert_eq!(read_config, vec![0; 10]);
399
400        entropy_dev.write_config(1, &write_config);
401        entropy_dev.read_config(1, &mut read_config);
402        assert_eq!(read_config, vec![0; 10]);
403
404        entropy_dev.write_config(2, &write_config);
405        entropy_dev.read_config(2, &mut read_config);
406        assert_eq!(read_config, vec![0; 10]);
407
408        entropy_dev.write_config(1024, &write_config);
409        entropy_dev.read_config(1024, &mut read_config);
410        assert_eq!(read_config, vec![0; 10]);
411    }
412
413    #[test]
414    fn test_handle_one() {
415        let mem = create_virtio_mem();
416        let mut th = VirtioTestHelper::<Entropy>::new(&mem, default_entropy());
417
418        // Checks that device activation works
419        th.activate_device(&mem);
420
421        // Add a read-only descriptor (this should fail)
422        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 64, 0)]);
423
424        // Add a write-only descriptor with 10 bytes
425        th.add_desc_chain(RNG_QUEUE, 0, &[(1, 10, VIRTQ_DESC_F_WRITE)]);
426
427        // Add a write-only descriptor with 0 bytes. This should not fail.
428        th.add_desc_chain(RNG_QUEUE, 0, &[(2, 0, VIRTQ_DESC_F_WRITE)]);
429
430        let mut entropy_dev = th.device();
431
432        // This should succeed, we just added two descriptors
433        let desc = entropy_dev.queues_mut()[RNG_QUEUE].pop().unwrap().unwrap();
434        assert!(matches!(
435            // SAFETY: This descriptor chain is only loaded into one buffer
436            unsafe { IoVecBufferMut::<256>::from_descriptor_chain(&mem, desc) },
437            Err(crate::devices::virtio::iovec::IoVecError::ReadOnlyDescriptor)
438        ));
439
440        // This should succeed, we should have one more descriptor
441        let desc = entropy_dev.queues_mut()[RNG_QUEUE].pop().unwrap().unwrap();
442        // SAFETY: This descriptor chain is only loaded into one buffer
443        entropy_dev.buffer = unsafe { IoVecBufferMut::from_descriptor_chain(&mem, desc).unwrap() };
444        entropy_dev.handle_one().unwrap();
445    }
446
447    #[test]
448    fn test_entropy_event() {
449        let mem = create_virtio_mem();
450        let mut th = VirtioTestHelper::<Entropy>::new(&mem, default_entropy());
451
452        th.activate_device(&mem);
453
454        // Add a read-only descriptor (this should fail)
455        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 64, 0)]);
456
457        let entropy_event_fails = METRICS.entropy_event_fails.count();
458        let entropy_event_count = METRICS.entropy_event_count.count();
459        let entropy_bytes = METRICS.entropy_bytes.count();
460        let host_rng_fails = METRICS.host_rng_fails.count();
461        assert_eq!(th.emulate_for_msec(100).unwrap(), 1);
462        assert_eq!(METRICS.entropy_event_fails.count(), entropy_event_fails + 1);
463        assert_eq!(METRICS.entropy_event_count.count(), entropy_event_count + 1);
464        assert_eq!(METRICS.entropy_bytes.count(), entropy_bytes);
465        assert_eq!(METRICS.host_rng_fails.count(), host_rng_fails);
466
467        // Add two good descriptors
468        th.add_desc_chain(RNG_QUEUE, 0, &[(1, 10, VIRTQ_DESC_F_WRITE)]);
469        th.add_desc_chain(RNG_QUEUE, 100, &[(2, 20, VIRTQ_DESC_F_WRITE)]);
470
471        let entropy_event_fails = METRICS.entropy_event_fails.count();
472        let entropy_event_count = METRICS.entropy_event_count.count();
473        let entropy_bytes = METRICS.entropy_bytes.count();
474        let host_rng_fails = METRICS.host_rng_fails.count();
475        assert_eq!(th.emulate_for_msec(100).unwrap(), 1);
476        assert_eq!(METRICS.entropy_event_fails.count(), entropy_event_fails);
477        assert_eq!(METRICS.entropy_event_count.count(), entropy_event_count + 2);
478        assert_eq!(METRICS.entropy_bytes.count(), entropy_bytes + 30);
479        assert_eq!(METRICS.host_rng_fails.count(), host_rng_fails);
480
481        th.add_desc_chain(
482            RNG_QUEUE,
483            0,
484            &[
485                (3, 128, VIRTQ_DESC_F_WRITE),
486                (4, 128, VIRTQ_DESC_F_WRITE),
487                (5, 256, VIRTQ_DESC_F_WRITE),
488            ],
489        );
490
491        let entropy_event_fails = METRICS.entropy_event_fails.count();
492        let entropy_event_count = METRICS.entropy_event_count.count();
493        let entropy_bytes = METRICS.entropy_bytes.count();
494        let host_rng_fails = METRICS.host_rng_fails.count();
495        assert_eq!(th.emulate_for_msec(100).unwrap(), 1);
496        assert_eq!(METRICS.entropy_event_fails.count(), entropy_event_fails);
497        assert_eq!(METRICS.entropy_event_count.count(), entropy_event_count + 1);
498        assert_eq!(METRICS.entropy_bytes.count(), entropy_bytes + 512);
499        assert_eq!(METRICS.host_rng_fails.count(), host_rng_fails);
500    }
501
502    #[test]
503    fn test_bad_rate_limiter_event() {
504        let mem = create_virtio_mem();
505        let mut th = VirtioTestHelper::<Entropy>::new(&mem, default_entropy());
506
507        th.activate_device(&mem);
508        let mut dev = th.device();
509
510        check_metric_after_block!(
511            &METRICS.entropy_event_fails,
512            1,
513            dev.process_rate_limiter_event()
514        );
515    }
516
517    #[test]
518    fn test_bandwidth_rate_limiter() {
519        let mem = create_virtio_mem();
520        // Rate Limiter with 4000 bytes / sec allowance and no initial burst allowance
521        let device = Entropy::new(RateLimiter::new(4000, 0, 1000, 0, 0, 0).unwrap()).unwrap();
522        let mut th = VirtioTestHelper::<Entropy>::new(&mem, device);
523
524        th.activate_device(&mem);
525
526        // We are asking for 4000 bytes which should be available, so the
527        // buffer should be processed normally
528        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 4000, VIRTQ_DESC_F_WRITE)]);
529        check_metric_after_block!(
530            METRICS.entropy_bytes,
531            4000,
532            th.device().process_entropy_queue()
533        );
534        assert!(!th.device().rate_limiter.is_blocked());
535
536        // Completely replenish the rate limiter
537        th.device()
538            .rate_limiter
539            .manual_replenish(4000, TokenType::Bytes);
540
541        // Add two descriptors. The first one should drain the available budget,
542        // so the next one should be throttled.
543        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 4000, VIRTQ_DESC_F_WRITE)]);
544        th.add_desc_chain(RNG_QUEUE, 1, &[(1, 1000, VIRTQ_DESC_F_WRITE)]);
545        check_metric_after_block!(
546            METRICS.entropy_bytes,
547            4000,
548            th.device().process_entropy_queue()
549        );
550        check_metric_after_block!(
551            METRICS.entropy_rate_limiter_throttled,
552            1,
553            th.device().process_entropy_queue()
554        );
555        assert!(th.device().rate_limiter().is_blocked());
556
557        // 250 msec should give enough time for replenishing 1000 bytes worth of tokens.
558        // Give it an extra 100 ms just to be sure the timer event reaches us from the kernel.
559        std::thread::sleep(Duration::from_millis(350));
560        check_metric_after_block!(METRICS.entropy_bytes, 1000, th.emulate_for_msec(100));
561        assert!(!th.device().rate_limiter().is_blocked());
562    }
563
564    #[test]
565    fn test_ops_rate_limiter() {
566        let mem = create_virtio_mem();
567        // Rate Limiter with unlimited bandwidth and allowance for 1 operation every 100 msec,
568        // (10 ops/sec), without initial burst.
569        let device = Entropy::new(RateLimiter::new(0, 0, 0, 1, 0, 100).unwrap()).unwrap();
570        let mut th = VirtioTestHelper::<Entropy>::new(&mem, device);
571
572        th.activate_device(&mem);
573
574        // We don't have a bandwidth limit and we can do 10 requests per sec
575        // so this should succeed.
576        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 4000, VIRTQ_DESC_F_WRITE)]);
577        check_metric_after_block!(
578            METRICS.entropy_bytes,
579            4000,
580            th.device().process_entropy_queue()
581        );
582        assert!(!th.device().rate_limiter.is_blocked());
583
584        // Sleep for 1 second to completely replenish the rate limiter
585        std::thread::sleep(Duration::from_millis(1000));
586
587        // First one should succeed
588        let entropy_bytes = METRICS.entropy_bytes.count();
589        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 64, VIRTQ_DESC_F_WRITE)]);
590        check_metric_after_block!(METRICS.entropy_bytes, 64, th.emulate_for_msec(100));
591        assert_eq!(METRICS.entropy_bytes.count(), entropy_bytes + 64);
592        // The rate limiter is not blocked yet.
593        assert!(!th.device().rate_limiter().is_blocked());
594        // But immediately asking another operation should block it because we have 1 op every 100
595        // msec.
596        th.add_desc_chain(RNG_QUEUE, 0, &[(0, 64, VIRTQ_DESC_F_WRITE)]);
597        check_metric_after_block!(
598            METRICS.entropy_rate_limiter_throttled,
599            1,
600            th.emulate_for_msec(50)
601        );
602        // Entropy bytes count should not have increased.
603        assert_eq!(METRICS.entropy_bytes.count(), entropy_bytes + 64);
604        // After 100 msec (plus 50 msec for ensuring the event reaches us from the kernel), the
605        // timer of the rate limiter should fire saying that there's now more tokens available
606        check_metric_after_block!(
607            METRICS.rate_limiter_event_count,
608            1,
609            th.emulate_for_msec(150)
610        );
611        // The rate limiter event should have processed the pending buffer as well
612        assert_eq!(METRICS.entropy_bytes.count(), entropy_bytes + 128);
613    }
614}