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