xref: /aosp_15_r20/external/crosvm/vm_control/src/balloon_tube.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Balloon related control APIs.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::VecDeque;
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail;
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
11*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
12*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonTubeCommand;
13*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonTubeResult;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::Error as SysError;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
17*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
18*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmResponse;
21*bb4ee6a4SAndroid Build Coastguard Worker 
22*bb4ee6a4SAndroid Build Coastguard Worker // Balloon commands that are sent on the crosvm control socket.
23*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Debug, Clone)]
24*bb4ee6a4SAndroid Build Coastguard Worker pub enum BalloonControlCommand {
25*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the size of the VM's balloon.
26*bb4ee6a4SAndroid Build Coastguard Worker     Adjust {
27*bb4ee6a4SAndroid Build Coastguard Worker         num_bytes: u64,
28*bb4ee6a4SAndroid Build Coastguard Worker         wait_for_success: bool,
29*bb4ee6a4SAndroid Build Coastguard Worker     },
30*bb4ee6a4SAndroid Build Coastguard Worker     Stats,
31*bb4ee6a4SAndroid Build Coastguard Worker     WorkingSet,
32*bb4ee6a4SAndroid Build Coastguard Worker     WorkingSetConfig {
33*bb4ee6a4SAndroid Build Coastguard Worker         bins: Vec<u32>,
34*bb4ee6a4SAndroid Build Coastguard Worker         refresh_threshold: u32,
35*bb4ee6a4SAndroid Build Coastguard Worker         report_threshold: u32,
36*bb4ee6a4SAndroid Build Coastguard Worker     },
37*bb4ee6a4SAndroid Build Coastguard Worker }
38*bb4ee6a4SAndroid Build Coastguard Worker 
do_send(tube: &Tube, cmd: &BalloonControlCommand) -> Option<VmResponse>39*bb4ee6a4SAndroid Build Coastguard Worker fn do_send(tube: &Tube, cmd: &BalloonControlCommand) -> Option<VmResponse> {
40*bb4ee6a4SAndroid Build Coastguard Worker     match *cmd {
41*bb4ee6a4SAndroid Build Coastguard Worker         BalloonControlCommand::Adjust {
42*bb4ee6a4SAndroid Build Coastguard Worker             num_bytes,
43*bb4ee6a4SAndroid Build Coastguard Worker             wait_for_success,
44*bb4ee6a4SAndroid Build Coastguard Worker         } => {
45*bb4ee6a4SAndroid Build Coastguard Worker             match tube.send(&BalloonTubeCommand::Adjust {
46*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes,
47*bb4ee6a4SAndroid Build Coastguard Worker                 allow_failure: wait_for_success,
48*bb4ee6a4SAndroid Build Coastguard Worker             }) {
49*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {
50*bb4ee6a4SAndroid Build Coastguard Worker                     if wait_for_success {
51*bb4ee6a4SAndroid Build Coastguard Worker                         None
52*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
53*bb4ee6a4SAndroid Build Coastguard Worker                         Some(VmResponse::Ok)
54*bb4ee6a4SAndroid Build Coastguard Worker                     }
55*bb4ee6a4SAndroid Build Coastguard Worker                 }
56*bb4ee6a4SAndroid Build Coastguard Worker                 Err(_) => Some(VmResponse::Err(SysError::last())),
57*bb4ee6a4SAndroid Build Coastguard Worker             }
58*bb4ee6a4SAndroid Build Coastguard Worker         }
59*bb4ee6a4SAndroid Build Coastguard Worker         BalloonControlCommand::WorkingSetConfig {
60*bb4ee6a4SAndroid Build Coastguard Worker             ref bins,
61*bb4ee6a4SAndroid Build Coastguard Worker             refresh_threshold,
62*bb4ee6a4SAndroid Build Coastguard Worker             report_threshold,
63*bb4ee6a4SAndroid Build Coastguard Worker         } => {
64*bb4ee6a4SAndroid Build Coastguard Worker             match tube.send(&BalloonTubeCommand::WorkingSetConfig {
65*bb4ee6a4SAndroid Build Coastguard Worker                 bins: bins.clone(),
66*bb4ee6a4SAndroid Build Coastguard Worker                 refresh_threshold,
67*bb4ee6a4SAndroid Build Coastguard Worker                 report_threshold,
68*bb4ee6a4SAndroid Build Coastguard Worker             }) {
69*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => Some(VmResponse::Ok),
70*bb4ee6a4SAndroid Build Coastguard Worker                 Err(_) => Some(VmResponse::Err(SysError::last())),
71*bb4ee6a4SAndroid Build Coastguard Worker             }
72*bb4ee6a4SAndroid Build Coastguard Worker         }
73*bb4ee6a4SAndroid Build Coastguard Worker         BalloonControlCommand::Stats => match tube.send(&BalloonTubeCommand::Stats) {
74*bb4ee6a4SAndroid Build Coastguard Worker             Ok(_) => None,
75*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => Some(VmResponse::Err(SysError::last())),
76*bb4ee6a4SAndroid Build Coastguard Worker         },
77*bb4ee6a4SAndroid Build Coastguard Worker         BalloonControlCommand::WorkingSet => match tube.send(&BalloonTubeCommand::WorkingSet) {
78*bb4ee6a4SAndroid Build Coastguard Worker             Ok(_) => None,
79*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => Some(VmResponse::Err(SysError::last())),
80*bb4ee6a4SAndroid Build Coastguard Worker         },
81*bb4ee6a4SAndroid Build Coastguard Worker     }
82*bb4ee6a4SAndroid Build Coastguard Worker }
83*bb4ee6a4SAndroid Build Coastguard Worker 
84*bb4ee6a4SAndroid Build Coastguard Worker /// Utility for multiplexing a balloon tube between multiple control tubes. Commands
85*bb4ee6a4SAndroid Build Coastguard Worker /// are sent and processed serially.
86*bb4ee6a4SAndroid Build Coastguard Worker pub struct BalloonTube {
87*bb4ee6a4SAndroid Build Coastguard Worker     tube: Tube,
88*bb4ee6a4SAndroid Build Coastguard Worker     pending_queue: VecDeque<(BalloonControlCommand, Option<usize>)>,
89*bb4ee6a4SAndroid Build Coastguard Worker     pending_adjust_with_completion: Option<(u64, usize)>,
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker impl BalloonTube {
new(tube: Tube) -> Self93*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(tube: Tube) -> Self {
94*bb4ee6a4SAndroid Build Coastguard Worker         BalloonTube {
95*bb4ee6a4SAndroid Build Coastguard Worker             tube,
96*bb4ee6a4SAndroid Build Coastguard Worker             pending_queue: VecDeque::new(),
97*bb4ee6a4SAndroid Build Coastguard Worker             pending_adjust_with_completion: None,
98*bb4ee6a4SAndroid Build Coastguard Worker         }
99*bb4ee6a4SAndroid Build Coastguard Worker     }
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker     /// Sends or queues the given command to this tube. Associates the
102*bb4ee6a4SAndroid Build Coastguard Worker     /// response with the given key.
send_cmd( &mut self, cmd: BalloonControlCommand, key: Option<usize>, ) -> Option<(VmResponse, usize)>103*bb4ee6a4SAndroid Build Coastguard Worker     pub fn send_cmd(
104*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
105*bb4ee6a4SAndroid Build Coastguard Worker         cmd: BalloonControlCommand,
106*bb4ee6a4SAndroid Build Coastguard Worker         key: Option<usize>,
107*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Option<(VmResponse, usize)> {
108*bb4ee6a4SAndroid Build Coastguard Worker         match cmd {
109*bb4ee6a4SAndroid Build Coastguard Worker             BalloonControlCommand::Adjust {
110*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: true,
111*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes,
112*bb4ee6a4SAndroid Build Coastguard Worker             } => {
113*bb4ee6a4SAndroid Build Coastguard Worker                 let Some(key) = key else {
114*bb4ee6a4SAndroid Build Coastguard Worker                     error!("Asked for completion without reply key");
115*bb4ee6a4SAndroid Build Coastguard Worker                     return None;
116*bb4ee6a4SAndroid Build Coastguard Worker                 };
117*bb4ee6a4SAndroid Build Coastguard Worker                 let resp = self
118*bb4ee6a4SAndroid Build Coastguard Worker                     .pending_adjust_with_completion
119*bb4ee6a4SAndroid Build Coastguard Worker                     .take()
120*bb4ee6a4SAndroid Build Coastguard Worker                     .map(|(_, key)| (VmResponse::ErrString("Adjust overriden".to_string()), key));
121*bb4ee6a4SAndroid Build Coastguard Worker                 if do_send(&self.tube, &cmd).is_some() {
122*bb4ee6a4SAndroid Build Coastguard Worker                     unreachable!("Unexpected early reply");
123*bb4ee6a4SAndroid Build Coastguard Worker                 }
124*bb4ee6a4SAndroid Build Coastguard Worker                 self.pending_adjust_with_completion = Some((num_bytes, key));
125*bb4ee6a4SAndroid Build Coastguard Worker                 resp
126*bb4ee6a4SAndroid Build Coastguard Worker             }
127*bb4ee6a4SAndroid Build Coastguard Worker             _ => {
128*bb4ee6a4SAndroid Build Coastguard Worker                 if !self.pending_queue.is_empty() {
129*bb4ee6a4SAndroid Build Coastguard Worker                     self.pending_queue.push_back((cmd, key));
130*bb4ee6a4SAndroid Build Coastguard Worker                     return None;
131*bb4ee6a4SAndroid Build Coastguard Worker                 }
132*bb4ee6a4SAndroid Build Coastguard Worker                 let resp = do_send(&self.tube, &cmd);
133*bb4ee6a4SAndroid Build Coastguard Worker                 if resp.is_none() {
134*bb4ee6a4SAndroid Build Coastguard Worker                     self.pending_queue.push_back((cmd, key));
135*bb4ee6a4SAndroid Build Coastguard Worker                 }
136*bb4ee6a4SAndroid Build Coastguard Worker                 match key {
137*bb4ee6a4SAndroid Build Coastguard Worker                     None => None,
138*bb4ee6a4SAndroid Build Coastguard Worker                     Some(key) => resp.map(|r| (r, key)),
139*bb4ee6a4SAndroid Build Coastguard Worker                 }
140*bb4ee6a4SAndroid Build Coastguard Worker             }
141*bb4ee6a4SAndroid Build Coastguard Worker         }
142*bb4ee6a4SAndroid Build Coastguard Worker     }
143*bb4ee6a4SAndroid Build Coastguard Worker 
144*bb4ee6a4SAndroid Build Coastguard Worker     /// Receives responses from the balloon tube, and returns them with
145*bb4ee6a4SAndroid Build Coastguard Worker     /// their assoicated keys.
recv(&mut self) -> Result<Vec<(VmResponse, usize)>>146*bb4ee6a4SAndroid Build Coastguard Worker     pub fn recv(&mut self) -> Result<Vec<(VmResponse, usize)>> {
147*bb4ee6a4SAndroid Build Coastguard Worker         let res = self
148*bb4ee6a4SAndroid Build Coastguard Worker             .tube
149*bb4ee6a4SAndroid Build Coastguard Worker             .recv::<BalloonTubeResult>()
150*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to read balloon tube")?;
151*bb4ee6a4SAndroid Build Coastguard Worker         if let BalloonTubeResult::Adjusted { num_bytes: actual } = res {
152*bb4ee6a4SAndroid Build Coastguard Worker             let Some((target, key)) = self.pending_adjust_with_completion else {
153*bb4ee6a4SAndroid Build Coastguard Worker                 bail!("Unexpected balloon adjust to {}", actual);
154*bb4ee6a4SAndroid Build Coastguard Worker             };
155*bb4ee6a4SAndroid Build Coastguard Worker             if actual != target {
156*bb4ee6a4SAndroid Build Coastguard Worker                 return Ok(vec![]);
157*bb4ee6a4SAndroid Build Coastguard Worker             }
158*bb4ee6a4SAndroid Build Coastguard Worker             self.pending_adjust_with_completion.take();
159*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(vec![(VmResponse::Ok, key)]);
160*bb4ee6a4SAndroid Build Coastguard Worker         }
161*bb4ee6a4SAndroid Build Coastguard Worker         let mut responses = vec![];
162*bb4ee6a4SAndroid Build Coastguard Worker         if self.pending_queue.is_empty() {
163*bb4ee6a4SAndroid Build Coastguard Worker             bail!("Unexpected balloon tube result {:?}", res)
164*bb4ee6a4SAndroid Build Coastguard Worker         }
165*bb4ee6a4SAndroid Build Coastguard Worker         let resp = match (
166*bb4ee6a4SAndroid Build Coastguard Worker             &self.pending_queue.front().expect("entry disappeared").0,
167*bb4ee6a4SAndroid Build Coastguard Worker             res,
168*bb4ee6a4SAndroid Build Coastguard Worker         ) {
169*bb4ee6a4SAndroid Build Coastguard Worker             (
170*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonControlCommand::Stats,
171*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonTubeResult::Stats {
172*bb4ee6a4SAndroid Build Coastguard Worker                     stats,
173*bb4ee6a4SAndroid Build Coastguard Worker                     balloon_actual,
174*bb4ee6a4SAndroid Build Coastguard Worker                 },
175*bb4ee6a4SAndroid Build Coastguard Worker             ) => VmResponse::BalloonStats {
176*bb4ee6a4SAndroid Build Coastguard Worker                 stats,
177*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_actual,
178*bb4ee6a4SAndroid Build Coastguard Worker             },
179*bb4ee6a4SAndroid Build Coastguard Worker             (
180*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonControlCommand::WorkingSet,
181*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonTubeResult::WorkingSet { ws, balloon_actual },
182*bb4ee6a4SAndroid Build Coastguard Worker             ) => VmResponse::BalloonWS { ws, balloon_actual },
183*bb4ee6a4SAndroid Build Coastguard Worker             (_, resp) => {
184*bb4ee6a4SAndroid Build Coastguard Worker                 bail!("Unexpected balloon tube result {:?}", resp);
185*bb4ee6a4SAndroid Build Coastguard Worker             }
186*bb4ee6a4SAndroid Build Coastguard Worker         };
187*bb4ee6a4SAndroid Build Coastguard Worker         let key = self.pending_queue.pop_front().expect("entry disappeared").1;
188*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(key) = key {
189*bb4ee6a4SAndroid Build Coastguard Worker             responses.push((resp, key))
190*bb4ee6a4SAndroid Build Coastguard Worker         }
191*bb4ee6a4SAndroid Build Coastguard Worker         while let Some((cmd, key)) = self.pending_queue.front() {
192*bb4ee6a4SAndroid Build Coastguard Worker             match do_send(&self.tube, cmd) {
193*bb4ee6a4SAndroid Build Coastguard Worker                 Some(resp) => {
194*bb4ee6a4SAndroid Build Coastguard Worker                     if let Some(key) = key {
195*bb4ee6a4SAndroid Build Coastguard Worker                         responses.push((resp, *key));
196*bb4ee6a4SAndroid Build Coastguard Worker                     }
197*bb4ee6a4SAndroid Build Coastguard Worker                     self.pending_queue.pop_front();
198*bb4ee6a4SAndroid Build Coastguard Worker                 }
199*bb4ee6a4SAndroid Build Coastguard Worker                 None => break,
200*bb4ee6a4SAndroid Build Coastguard Worker             }
201*bb4ee6a4SAndroid Build Coastguard Worker         }
202*bb4ee6a4SAndroid Build Coastguard Worker         Ok(responses)
203*bb4ee6a4SAndroid Build Coastguard Worker     }
204*bb4ee6a4SAndroid Build Coastguard Worker }
205*bb4ee6a4SAndroid Build Coastguard Worker 
206*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
207*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
208*bb4ee6a4SAndroid Build Coastguard Worker     use balloon_control::BalloonStats;
209*bb4ee6a4SAndroid Build Coastguard Worker 
210*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
211*bb4ee6a4SAndroid Build Coastguard Worker 
balloon_device_respond_stats(device: &Tube)212*bb4ee6a4SAndroid Build Coastguard Worker     fn balloon_device_respond_stats(device: &Tube) {
213*bb4ee6a4SAndroid Build Coastguard Worker         let BalloonTubeCommand::Stats = device.recv::<BalloonTubeCommand>().unwrap() else {
214*bb4ee6a4SAndroid Build Coastguard Worker             panic!("unexpected command");
215*bb4ee6a4SAndroid Build Coastguard Worker         };
216*bb4ee6a4SAndroid Build Coastguard Worker 
217*bb4ee6a4SAndroid Build Coastguard Worker         device
218*bb4ee6a4SAndroid Build Coastguard Worker             .send(&BalloonTubeResult::Stats {
219*bb4ee6a4SAndroid Build Coastguard Worker                 stats: BalloonStats::default(),
220*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_actual: 0,
221*bb4ee6a4SAndroid Build Coastguard Worker             })
222*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
223*bb4ee6a4SAndroid Build Coastguard Worker     }
224*bb4ee6a4SAndroid Build Coastguard Worker 
225*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_stat_command()226*bb4ee6a4SAndroid Build Coastguard Worker     fn test_stat_command() {
227*bb4ee6a4SAndroid Build Coastguard Worker         let (host, device) = Tube::pair().unwrap();
228*bb4ee6a4SAndroid Build Coastguard Worker         let mut balloon_tube = BalloonTube::new(host);
229*bb4ee6a4SAndroid Build Coastguard Worker 
230*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(BalloonControlCommand::Stats, Some(0xc0ffee));
231*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
232*bb4ee6a4SAndroid Build Coastguard Worker 
233*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_respond_stats(&device);
234*bb4ee6a4SAndroid Build Coastguard Worker 
235*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
236*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 1);
237*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xc0ffee);
238*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::BalloonStats { .. }));
239*bb4ee6a4SAndroid Build Coastguard Worker     }
240*bb4ee6a4SAndroid Build Coastguard Worker 
241*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_multiple_stat_command()242*bb4ee6a4SAndroid Build Coastguard Worker     fn test_multiple_stat_command() {
243*bb4ee6a4SAndroid Build Coastguard Worker         let (host, device) = Tube::pair().unwrap();
244*bb4ee6a4SAndroid Build Coastguard Worker         let mut balloon_tube = BalloonTube::new(host);
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(BalloonControlCommand::Stats, Some(0xc0ffee));
247*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
248*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(BalloonControlCommand::Stats, Some(0xbadcafe));
249*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
250*bb4ee6a4SAndroid Build Coastguard Worker 
251*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_respond_stats(&device);
252*bb4ee6a4SAndroid Build Coastguard Worker 
253*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
254*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 1);
255*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xc0ffee);
256*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::BalloonStats { .. }));
257*bb4ee6a4SAndroid Build Coastguard Worker 
258*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_respond_stats(&device);
259*bb4ee6a4SAndroid Build Coastguard Worker 
260*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
261*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 1);
262*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xbadcafe);
263*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::BalloonStats { .. }));
264*bb4ee6a4SAndroid Build Coastguard Worker     }
265*bb4ee6a4SAndroid Build Coastguard Worker 
266*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_queued_stats_adjust_no_reply()267*bb4ee6a4SAndroid Build Coastguard Worker     fn test_queued_stats_adjust_no_reply() {
268*bb4ee6a4SAndroid Build Coastguard Worker         let (host, device) = Tube::pair().unwrap();
269*bb4ee6a4SAndroid Build Coastguard Worker         let mut balloon_tube = BalloonTube::new(host);
270*bb4ee6a4SAndroid Build Coastguard Worker 
271*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(BalloonControlCommand::Stats, Some(0xc0ffee));
272*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
273*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(
274*bb4ee6a4SAndroid Build Coastguard Worker             BalloonControlCommand::Adjust {
275*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0,
276*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: false,
277*bb4ee6a4SAndroid Build Coastguard Worker             },
278*bb4ee6a4SAndroid Build Coastguard Worker             Some(0xbadcafe),
279*bb4ee6a4SAndroid Build Coastguard Worker         );
280*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
281*bb4ee6a4SAndroid Build Coastguard Worker 
282*bb4ee6a4SAndroid Build Coastguard Worker         balloon_device_respond_stats(&device);
283*bb4ee6a4SAndroid Build Coastguard Worker 
284*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
285*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 2);
286*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xc0ffee);
287*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::BalloonStats { .. }));
288*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[1].1, 0xbadcafe);
289*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[1].0, VmResponse::Ok));
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker         let cmd = device.recv::<BalloonTubeCommand>().unwrap();
292*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(cmd, BalloonTubeCommand::Adjust { .. }));
293*bb4ee6a4SAndroid Build Coastguard Worker     }
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_adjust_with_reply()296*bb4ee6a4SAndroid Build Coastguard Worker     fn test_adjust_with_reply() {
297*bb4ee6a4SAndroid Build Coastguard Worker         let (host, device) = Tube::pair().unwrap();
298*bb4ee6a4SAndroid Build Coastguard Worker         let mut balloon_tube = BalloonTube::new(host);
299*bb4ee6a4SAndroid Build Coastguard Worker 
300*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(
301*bb4ee6a4SAndroid Build Coastguard Worker             BalloonControlCommand::Adjust {
302*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0xc0ffee,
303*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: true,
304*bb4ee6a4SAndroid Build Coastguard Worker             },
305*bb4ee6a4SAndroid Build Coastguard Worker             Some(0xc0ffee),
306*bb4ee6a4SAndroid Build Coastguard Worker         );
307*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
308*bb4ee6a4SAndroid Build Coastguard Worker         let cmd = device.recv::<BalloonTubeCommand>().unwrap();
309*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(cmd, BalloonTubeCommand::Adjust { .. }));
310*bb4ee6a4SAndroid Build Coastguard Worker 
311*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(
312*bb4ee6a4SAndroid Build Coastguard Worker             BalloonControlCommand::Adjust {
313*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0xbadcafe,
314*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: true,
315*bb4ee6a4SAndroid Build Coastguard Worker             },
316*bb4ee6a4SAndroid Build Coastguard Worker             Some(0xbadcafe),
317*bb4ee6a4SAndroid Build Coastguard Worker         );
318*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp, Some((VmResponse::ErrString(_), 0xc0ffee))));
319*bb4ee6a4SAndroid Build Coastguard Worker         let cmd = device.recv::<BalloonTubeCommand>().unwrap();
320*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(cmd, BalloonTubeCommand::Adjust { .. }));
321*bb4ee6a4SAndroid Build Coastguard Worker 
322*bb4ee6a4SAndroid Build Coastguard Worker         device
323*bb4ee6a4SAndroid Build Coastguard Worker             .send(&BalloonTubeResult::Adjusted {
324*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0xc0ffee,
325*bb4ee6a4SAndroid Build Coastguard Worker             })
326*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
327*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
328*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 0);
329*bb4ee6a4SAndroid Build Coastguard Worker 
330*bb4ee6a4SAndroid Build Coastguard Worker         device
331*bb4ee6a4SAndroid Build Coastguard Worker             .send(&BalloonTubeResult::Adjusted {
332*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0xbadcafe,
333*bb4ee6a4SAndroid Build Coastguard Worker             })
334*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
335*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
336*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 1);
337*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xbadcafe);
338*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::Ok));
339*bb4ee6a4SAndroid Build Coastguard Worker     }
340*bb4ee6a4SAndroid Build Coastguard Worker 
341*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_stats_and_adjust_with_reply()342*bb4ee6a4SAndroid Build Coastguard Worker     fn test_stats_and_adjust_with_reply() {
343*bb4ee6a4SAndroid Build Coastguard Worker         let (host, device) = Tube::pair().unwrap();
344*bb4ee6a4SAndroid Build Coastguard Worker         let mut balloon_tube = BalloonTube::new(host);
345*bb4ee6a4SAndroid Build Coastguard Worker 
346*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(BalloonControlCommand::Stats, Some(0xc0ffee));
347*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
348*bb4ee6a4SAndroid Build Coastguard Worker 
349*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.send_cmd(
350*bb4ee6a4SAndroid Build Coastguard Worker             BalloonControlCommand::Adjust {
351*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0xbadcafe,
352*bb4ee6a4SAndroid Build Coastguard Worker                 wait_for_success: true,
353*bb4ee6a4SAndroid Build Coastguard Worker             },
354*bb4ee6a4SAndroid Build Coastguard Worker             Some(0xbadcafe),
355*bb4ee6a4SAndroid Build Coastguard Worker         );
356*bb4ee6a4SAndroid Build Coastguard Worker         assert!(resp.is_none());
357*bb4ee6a4SAndroid Build Coastguard Worker 
358*bb4ee6a4SAndroid Build Coastguard Worker         let cmd = device.recv::<BalloonTubeCommand>().unwrap();
359*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(cmd, BalloonTubeCommand::Stats));
360*bb4ee6a4SAndroid Build Coastguard Worker         let cmd = device.recv::<BalloonTubeCommand>().unwrap();
361*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(cmd, BalloonTubeCommand::Adjust { .. }));
362*bb4ee6a4SAndroid Build Coastguard Worker 
363*bb4ee6a4SAndroid Build Coastguard Worker         device
364*bb4ee6a4SAndroid Build Coastguard Worker             .send(&BalloonTubeResult::Adjusted {
365*bb4ee6a4SAndroid Build Coastguard Worker                 num_bytes: 0xbadcafe,
366*bb4ee6a4SAndroid Build Coastguard Worker             })
367*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
368*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
369*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 1);
370*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xbadcafe);
371*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::Ok));
372*bb4ee6a4SAndroid Build Coastguard Worker 
373*bb4ee6a4SAndroid Build Coastguard Worker         device
374*bb4ee6a4SAndroid Build Coastguard Worker             .send(&BalloonTubeResult::Stats {
375*bb4ee6a4SAndroid Build Coastguard Worker                 stats: BalloonStats::default(),
376*bb4ee6a4SAndroid Build Coastguard Worker                 balloon_actual: 0,
377*bb4ee6a4SAndroid Build Coastguard Worker             })
378*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
379*bb4ee6a4SAndroid Build Coastguard Worker         let resp = balloon_tube.recv().unwrap();
380*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp.len(), 1);
381*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(resp[0].1, 0xc0ffee);
382*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(resp[0].0, VmResponse::BalloonStats { .. }));
383*bb4ee6a4SAndroid Build Coastguard Worker     }
384*bb4ee6a4SAndroid Build Coastguard Worker }
385