Skip to content

Commit 347f877

Browse files
committed
unittest: net: eliminate ReadTapMock::MockFrame
The test code has two ways to inject a packet to be read from the tap device: Using the `TapTrafficSimulator`, which actually uses `sendto` to send something through the tap device, or `MockFrame`, which hijacks `Net::read_tap` to not actually read from the tap and just return the packet. Eliminate the latter, as it was only used in a single test, and needless complicates the test setup (well, arguably, unittests shouldn't use actual Tap devices, and thus we should eliminte `TapTrafficSimulator` instead, but I'm choosing my battles today). Do the injection of the packet before we deplete the ratelimiter, as otherwise the injection takes long enough for the ratelimiter to replenish, causing the test to fail intermittently. Also increase the replenish time. Signed-off-by: Patrick Roy <[email protected]>
1 parent 0396026 commit 347f877

File tree

2 files changed

+30
-41
lines changed

2 files changed

+30
-41
lines changed

src/vmm/src/devices/virtio/net/device.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -964,10 +964,6 @@ pub mod tests {
964964
impl Net {
965965
pub(crate) fn read_tap(&mut self) -> io::Result<usize> {
966966
match &self.tap.mocks.read_tap {
967-
ReadTapMock::MockFrame(frame) => {
968-
self.rx_frame_buf[..frame.len()].copy_from_slice(frame);
969-
Ok(frame.len())
970-
}
971967
ReadTapMock::Failure => Err(io::Error::new(
972968
io::ErrorKind::Other,
973969
"Read tap synthetically failed.",
@@ -1911,18 +1907,22 @@ pub mod tests {
19111907

19121908
// Test RX bandwidth rate limiting
19131909
{
1914-
// create bandwidth rate limiter that allows 40960 bytes/s with bucket size 4096 bytes
1915-
let mut rl = RateLimiter::new(0x1000, 0, 100, 0, 0, 0).unwrap();
1916-
// use up the budget
1917-
assert!(rl.consume(0x1000, TokenType::Bytes));
1918-
1919-
// set this rx rate limiter to be used
1920-
th.net().rx_rate_limiter = rl;
1910+
// create bandwidth rate limiter that allows 2000 bytes/s with bucket size 1000 bytes
1911+
let mut rl = RateLimiter::new(1000, 0, 500, 0, 0, 0).unwrap();
19211912

19221913
// set up RX
19231914
assert!(!th.net().rx_deferred_frame);
19241915
th.add_desc_chain(NetQueue::Rx, 0, &[(0, 4096, VIRTQ_DESC_F_WRITE)]);
19251916

1917+
let frame = inject_tap_tx_frame(&th.net(), 1000);
1918+
1919+
// use up the budget (do it after injecting the tx frame, as socket communication is
1920+
// slow enough that the ratelimiter could replenish in the meantime).
1921+
assert!(rl.consume(1000, TokenType::Bytes));
1922+
1923+
// set this rx rate limiter to be used
1924+
th.net().rx_rate_limiter = rl;
1925+
19261926
// following RX procedure should fail because of bandwidth rate limiting
19271927
{
19281928
// trigger the RX handler
@@ -1946,13 +1946,12 @@ pub mod tests {
19461946
assert_eq!(th.net().metrics.rx_rate_limiter_throttled.count(), 2);
19471947
}
19481948

1949-
// wait for 100ms to give the rate-limiter timer a chance to replenish
1950-
// wait for an extra 100ms to make sure the timerfd event makes its way from the kernel
1951-
thread::sleep(Duration::from_millis(200));
1949+
// wait for 500ms to give the rate-limiter timer a chance to replenish
1950+
// wait for an extra 500ms to make sure the timerfd event makes its way from the kernel
1951+
thread::sleep(Duration::from_millis(1000));
19521952

19531953
// following RX procedure should succeed because bandwidth should now be available
19541954
{
1955-
let frame = &th.net().tap.mocks.read_tap.mock_frame();
19561955
// no longer throttled
19571956
check_metric_after_block!(
19581957
th.net().metrics.rx_rate_limiter_throttled,
@@ -1967,7 +1966,7 @@ pub mod tests {
19671966
assert_eq!(th.rxq.used.idx.get(), 1);
19681967
th.rxq
19691968
.check_used_elem(0, 0, frame.len().try_into().unwrap());
1970-
th.rxq.dtable[0].check_data(frame);
1969+
th.rxq.dtable[0].check_data(&frame);
19711970
}
19721971
}
19731972
}
@@ -2025,18 +2024,20 @@ pub mod tests {
20252024

20262025
// Test RX ops rate limiting
20272026
{
2028-
// create ops rate limiter that allows 10 ops/s with bucket size 1 ops
2029-
let mut rl = RateLimiter::new(0, 0, 0, 1, 0, 100).unwrap();
2027+
// create ops rate limiter that allows 2 ops/s with bucket size 1 ops
2028+
let mut rl = RateLimiter::new(0, 0, 0, 1, 0, 500).unwrap();
2029+
2030+
// set up RX
2031+
assert!(!th.net().rx_deferred_frame);
2032+
th.add_desc_chain(NetQueue::Rx, 0, &[(0, 4096, VIRTQ_DESC_F_WRITE)]);
2033+
let frame = inject_tap_tx_frame(&th.net(), 1234);
2034+
20302035
// use up the initial budget
20312036
assert!(rl.consume(1, TokenType::Ops));
20322037

20332038
// set this rx rate limiter to be used
20342039
th.net().rx_rate_limiter = rl;
20352040

2036-
// set up RX
2037-
assert!(!th.net().rx_deferred_frame);
2038-
th.add_desc_chain(NetQueue::Rx, 0, &[(0, 4096, VIRTQ_DESC_F_WRITE)]);
2039-
20402041
// following RX procedure should fail because of ops rate limiting
20412042
{
20422043
// trigger the RX handler
@@ -2063,21 +2064,20 @@ pub mod tests {
20632064
assert_eq!(th.rxq.used.idx.get(), 0);
20642065
}
20652066

2066-
// wait for 100ms to give the rate-limiter timer a chance to replenish
2067-
// wait for an extra 100ms to make sure the timerfd event makes its way from the kernel
2068-
thread::sleep(Duration::from_millis(200));
2067+
// wait for 500ms to give the rate-limiter timer a chance to replenish
2068+
// wait for an extra 500ms to make sure the timerfd event makes its way from the kernel
2069+
thread::sleep(Duration::from_millis(1000));
20692070

20702071
// following RX procedure should succeed because ops should now be available
20712072
{
2072-
let frame = &th.net().tap.mocks.read_tap.mock_frame();
20732073
th.simulate_event(NetEvent::RxRateLimiter);
20742074
// make sure the virtio queue operation completed this time
20752075
assert!(&th.net().irq_trigger.has_pending_irq(IrqType::Vring));
20762076
// make sure the data queue advanced
20772077
assert_eq!(th.rxq.used.idx.get(), 1);
20782078
th.rxq
20792079
.check_used_elem(0, 0, frame.len().try_into().unwrap());
2080-
th.rxq.dtable[0].check_data(frame);
2080+
th.rxq.dtable[0].check_data(&frame);
20812081
}
20822082
}
20832083
}

src/vmm/src/devices/virtio/net/test_utils.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use std::fs::File;
77
use std::mem;
88
use std::os::raw::c_ulong;
9-
use std::os::unix::ffi::OsStrExt;
109
use std::os::unix::io::{AsRawFd, FromRawFd};
1110
use std::process::Command;
1211
use std::str::FromStr;
@@ -80,19 +79,9 @@ pub fn default_net_no_mmds() -> Net {
8079
#[derive(Debug)]
8180
pub enum ReadTapMock {
8281
Failure,
83-
MockFrame(Vec<u8>),
8482
TapFrame,
8583
}
8684

87-
impl ReadTapMock {
88-
pub fn mock_frame(&self) -> Vec<u8> {
89-
if let ReadTapMock::MockFrame(frame) = self {
90-
return frame.clone();
91-
}
92-
panic!("Can't get last mock frame");
93-
}
94-
}
95-
9685
#[derive(Debug)]
9786
pub enum WriteTapMock {
9887
Failure,
@@ -119,9 +108,7 @@ impl Mocks {
119108
impl Default for Mocks {
120109
fn default() -> Mocks {
121110
Mocks {
122-
read_tap: ReadTapMock::MockFrame(
123-
utils::rand::rand_alphanumerics(1234).as_bytes().to_vec(),
124-
),
111+
read_tap: ReadTapMock::TapFrame,
125112
write_tap: WriteTapMock::Success,
126113
}
127114
}
@@ -298,6 +285,8 @@ pub fn enable(tap: &Tap) {
298285

299286
#[cfg(test)]
300287
pub(crate) fn inject_tap_tx_frame(net: &Net, len: usize) -> Vec<u8> {
288+
use std::os::unix::ffi::OsStrExt;
289+
301290
assert!(len >= vnet_hdr_len());
302291
let tap_traffic_simulator = TapTrafficSimulator::new(if_index(&net.tap));
303292
let mut frame = utils::rand::rand_alphanumerics(len - vnet_hdr_len())

0 commit comments

Comments
 (0)