vmm/devices/virtio/net/
event_handler.rs

1// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use event_manager::{EventOps, Events, MutEventSubscriber};
5use vmm_sys_util::epoll::EventSet;
6
7use crate::devices::virtio::device::VirtioDevice;
8use crate::devices::virtio::net::device::Net;
9use crate::devices::virtio::net::{RX_INDEX, TX_INDEX};
10use crate::logger::{IncMetric, error, warn};
11
12impl Net {
13    const PROCESS_ACTIVATE: u32 = 0;
14    const PROCESS_VIRTQ_RX: u32 = 1;
15    const PROCESS_VIRTQ_TX: u32 = 2;
16    const PROCESS_TAP_RX: u32 = 3;
17    const PROCESS_RX_RATE_LIMITER: u32 = 4;
18    const PROCESS_TX_RATE_LIMITER: u32 = 5;
19
20    fn register_runtime_events(&self, ops: &mut EventOps) {
21        if let Err(err) = ops.add(Events::with_data(
22            &self.queue_evts[RX_INDEX],
23            Self::PROCESS_VIRTQ_RX,
24            EventSet::IN,
25        )) {
26            error!("Failed to register rx queue event: {}", err);
27        }
28        if let Err(err) = ops.add(Events::with_data(
29            &self.queue_evts[TX_INDEX],
30            Self::PROCESS_VIRTQ_TX,
31            EventSet::IN,
32        )) {
33            error!("Failed to register tx queue event: {}", err);
34        }
35        if let Err(err) = ops.add(Events::with_data(
36            &self.rx_rate_limiter,
37            Self::PROCESS_RX_RATE_LIMITER,
38            EventSet::IN,
39        )) {
40            error!("Failed to register rx queue event: {}", err);
41        }
42        if let Err(err) = ops.add(Events::with_data(
43            &self.tx_rate_limiter,
44            Self::PROCESS_TX_RATE_LIMITER,
45            EventSet::IN,
46        )) {
47            error!("Failed to register tx queue event: {}", err);
48        }
49        if let Err(err) = ops.add(Events::with_data(
50            &self.tap,
51            Self::PROCESS_TAP_RX,
52            EventSet::IN | EventSet::EDGE_TRIGGERED,
53        )) {
54            error!("Failed to register tap event: {}", err);
55        }
56    }
57
58    fn register_activate_event(&self, ops: &mut EventOps) {
59        if let Err(err) = ops.add(Events::with_data(
60            &self.activate_evt,
61            Self::PROCESS_ACTIVATE,
62            EventSet::IN,
63        )) {
64            error!("Failed to register activate event: {}", err);
65        }
66    }
67
68    fn process_activate_event(&self, ops: &mut EventOps) {
69        if let Err(err) = self.activate_evt.read() {
70            error!("Failed to consume net activate event: {:?}", err);
71        }
72        self.register_runtime_events(ops);
73        if let Err(err) = ops.remove(Events::with_data(
74            &self.activate_evt,
75            Self::PROCESS_ACTIVATE,
76            EventSet::IN,
77        )) {
78            error!("Failed to un-register activate event: {}", err);
79        }
80    }
81}
82
83impl MutEventSubscriber for Net {
84    fn process(&mut self, event: Events, ops: &mut EventOps) {
85        let source = event.data();
86        let event_set = event.event_set();
87
88        // TODO: also check for errors. Pending high level discussions on how we want
89        // to handle errors in devices.
90        let supported_events = EventSet::IN;
91        if !supported_events.contains(event_set) {
92            warn!(
93                "Received unknown event: {:?} from source: {:?}",
94                event_set, source
95            );
96            return;
97        }
98
99        if self.is_activated() {
100            match source {
101                Self::PROCESS_ACTIVATE => self.process_activate_event(ops),
102                Self::PROCESS_VIRTQ_RX => self.process_rx_queue_event(),
103                Self::PROCESS_VIRTQ_TX => self.process_tx_queue_event(),
104                Self::PROCESS_TAP_RX => self.process_tap_rx_event(),
105                Self::PROCESS_RX_RATE_LIMITER => self.process_rx_rate_limiter_event(),
106                Self::PROCESS_TX_RATE_LIMITER => self.process_tx_rate_limiter_event(),
107                _ => {
108                    warn!("Net: Spurious event received: {:?}", source);
109                    self.metrics.event_fails.inc();
110                }
111            }
112        } else {
113            warn!(
114                "Net: The device is not yet activated. Spurious event received: {:?}",
115                source
116            );
117        }
118    }
119
120    fn init(&mut self, ops: &mut EventOps) {
121        // This function can be called during different points in the device lifetime:
122        //  - shortly after device creation,
123        //  - on device activation (is-activated already true at this point),
124        //  - on device restore from snapshot.
125        if self.is_activated() {
126            self.register_runtime_events(ops);
127        } else {
128            self.register_activate_event(ops);
129        }
130    }
131}
132
133#[cfg(test)]
134pub mod tests {
135    use crate::devices::virtio::net::test_utils::NetQueue;
136    use crate::devices::virtio::net::test_utils::test::TestHelper;
137    use crate::devices::virtio::net::{MAX_BUFFER_SIZE, TX_INDEX};
138    use crate::test_utils::single_region_mem;
139
140    #[test]
141    fn test_event_handler() {
142        let mem = single_region_mem(2 * MAX_BUFFER_SIZE);
143        let mut th = TestHelper::get_default(&mem);
144
145        // Push a queue event, use the TX_QUEUE_EVENT in this test.
146        th.add_desc_chain(NetQueue::Tx, 0, &[(0, 4096, 0)]);
147
148        // EventManager should report no events since net has only registered
149        // its activation event so far (even though there is also a queue event pending).
150        let ev_count = th.event_manager.run_with_timeout(50).unwrap();
151        assert_eq!(ev_count, 0);
152
153        // Manually force a queue event and check it's ignored pre-activation.
154        th.net().queue_evts[TX_INDEX].write(1).unwrap();
155        let ev_count = th.event_manager.run_with_timeout(50).unwrap();
156        assert_eq!(ev_count, 0);
157        // Validate there was no queue operation.
158        assert_eq!(th.txq.used.idx.get(), 0);
159
160        // Now activate the device.
161        th.activate_net();
162        // Handle the previously pushed queue event through EventManager.
163        th.event_manager
164            .run_with_timeout(50)
165            .expect("Metrics event timeout or error.");
166        // Make sure the data queue advanced.
167        assert_eq!(th.txq.used.idx.get(), 1);
168    }
169}