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 //! Integration test for hotplug of tap devices as virtio-net.
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(all(unix, target_arch = "x86_64"))]
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use std::net::Ipv4Addr;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::process::Command;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::thread;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant;
14*bb4ee6a4SAndroid Build Coastguard Worker
15*bb4ee6a4SAndroid Build Coastguard Worker use base::sys::linux::ioctl_with_val;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::test_utils::call_test_with_sudo;
17*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::Config;
18*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::TestVm;
19*bb4ee6a4SAndroid Build Coastguard Worker use net_util::sys::linux::Tap;
20*bb4ee6a4SAndroid Build Coastguard Worker use net_util::sys::linux::TapTLinux;
21*bb4ee6a4SAndroid Build Coastguard Worker use net_util::MacAddress;
22*bb4ee6a4SAndroid Build Coastguard Worker use net_util::TapTCommon;
23*bb4ee6a4SAndroid Build Coastguard Worker
24*bb4ee6a4SAndroid Build Coastguard Worker /// Count the number of virtio-net devices.
count_virtio_net_devices(vm: &mut TestVm) -> usize25*bb4ee6a4SAndroid Build Coastguard Worker fn count_virtio_net_devices(vm: &mut TestVm) -> usize {
26*bb4ee6a4SAndroid Build Coastguard Worker let lspci_result = vm.exec_in_guest("lspci -n").unwrap();
27*bb4ee6a4SAndroid Build Coastguard Worker // Count occurance for virtio net device: 1af4:1041
28*bb4ee6a4SAndroid Build Coastguard Worker lspci_result.stdout.matches("1af4:1041").count()
29*bb4ee6a4SAndroid Build Coastguard Worker }
30*bb4ee6a4SAndroid Build Coastguard Worker
31*bb4ee6a4SAndroid Build Coastguard Worker /// Poll func until it returns true, or timeout is exceeded.
poll_until_true<F>(vm: &mut TestVm, func: F, timeout: Duration) -> bool where F: Fn(&mut TestVm) -> bool,32*bb4ee6a4SAndroid Build Coastguard Worker fn poll_until_true<F>(vm: &mut TestVm, func: F, timeout: Duration) -> bool
33*bb4ee6a4SAndroid Build Coastguard Worker where
34*bb4ee6a4SAndroid Build Coastguard Worker F: Fn(&mut TestVm) -> bool,
35*bb4ee6a4SAndroid Build Coastguard Worker {
36*bb4ee6a4SAndroid Build Coastguard Worker let poll_interval = Duration::from_millis(100);
37*bb4ee6a4SAndroid Build Coastguard Worker let start_time = Instant::now();
38*bb4ee6a4SAndroid Build Coastguard Worker while !func(vm) {
39*bb4ee6a4SAndroid Build Coastguard Worker if start_time.elapsed() > timeout {
40*bb4ee6a4SAndroid Build Coastguard Worker return false;
41*bb4ee6a4SAndroid Build Coastguard Worker }
42*bb4ee6a4SAndroid Build Coastguard Worker thread::sleep(poll_interval);
43*bb4ee6a4SAndroid Build Coastguard Worker }
44*bb4ee6a4SAndroid Build Coastguard Worker true
45*bb4ee6a4SAndroid Build Coastguard Worker }
46*bb4ee6a4SAndroid Build Coastguard Worker
47*bb4ee6a4SAndroid Build Coastguard Worker /// setup a tap device for test
setup_tap_device(tap_name: &[u8], ip_addr: Ipv4Addr, netmask: Ipv4Addr, mac_addr: MacAddress)48*bb4ee6a4SAndroid Build Coastguard Worker fn setup_tap_device(tap_name: &[u8], ip_addr: Ipv4Addr, netmask: Ipv4Addr, mac_addr: MacAddress) {
49*bb4ee6a4SAndroid Build Coastguard Worker let tap = Tap::new_with_name(tap_name, true, false).unwrap();
50*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
51*bb4ee6a4SAndroid Build Coastguard Worker // ioctl is safe since we call it with a valid tap fd and check the return value.
52*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { ioctl_with_val(&tap, net_sys::TUNSETPERSIST, 1) };
53*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 {
54*bb4ee6a4SAndroid Build Coastguard Worker panic!("Failed to persist tap interface");
55*bb4ee6a4SAndroid Build Coastguard Worker }
56*bb4ee6a4SAndroid Build Coastguard Worker tap.set_ip_addr(ip_addr).unwrap();
57*bb4ee6a4SAndroid Build Coastguard Worker tap.set_netmask(netmask).unwrap();
58*bb4ee6a4SAndroid Build Coastguard Worker tap.set_mac_address(mac_addr).unwrap();
59*bb4ee6a4SAndroid Build Coastguard Worker tap.set_vnet_hdr_size(16).unwrap();
60*bb4ee6a4SAndroid Build Coastguard Worker tap.set_offload(0).unwrap();
61*bb4ee6a4SAndroid Build Coastguard Worker tap.enable().unwrap();
62*bb4ee6a4SAndroid Build Coastguard Worker // Release tap to be used by the VM.
63*bb4ee6a4SAndroid Build Coastguard Worker drop(tap);
64*bb4ee6a4SAndroid Build Coastguard Worker }
65*bb4ee6a4SAndroid Build Coastguard Worker
66*bb4ee6a4SAndroid Build Coastguard Worker /// Implementation for tap_hotplug_two
67*bb4ee6a4SAndroid Build Coastguard Worker ///
68*bb4ee6a4SAndroid Build Coastguard Worker /// This test will fail by itself due to permission.
69*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by tap_hotplug_two"]
70*bb4ee6a4SAndroid Build Coastguard Worker #[test]
tap_hotplug_two_impl()71*bb4ee6a4SAndroid Build Coastguard Worker fn tap_hotplug_two_impl() {
72*bb4ee6a4SAndroid Build Coastguard Worker let wait_timeout = Duration::from_secs(5);
73*bb4ee6a4SAndroid Build Coastguard Worker // Setup VM start parameter.
74*bb4ee6a4SAndroid Build Coastguard Worker let config = Config::new().extra_args(vec!["--pci-hotplug-slots".to_owned(), "2".to_owned()]);
75*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
76*bb4ee6a4SAndroid Build Coastguard Worker
77*bb4ee6a4SAndroid Build Coastguard Worker //Setup test taps. tap_name has to be distinct per test, or it may appear flaky (b/333090169).
78*bb4ee6a4SAndroid Build Coastguard Worker let tap1_name = "test_tap1";
79*bb4ee6a4SAndroid Build Coastguard Worker setup_tap_device(
80*bb4ee6a4SAndroid Build Coastguard Worker tap1_name.as_bytes(),
81*bb4ee6a4SAndroid Build Coastguard Worker "100.115.92.15".parse().unwrap(),
82*bb4ee6a4SAndroid Build Coastguard Worker "255.255.255.252".parse().unwrap(),
83*bb4ee6a4SAndroid Build Coastguard Worker "a0:b0:c0:d0:e0:f1".parse().unwrap(),
84*bb4ee6a4SAndroid Build Coastguard Worker );
85*bb4ee6a4SAndroid Build Coastguard Worker let tap2_name = "test_tap2";
86*bb4ee6a4SAndroid Build Coastguard Worker setup_tap_device(
87*bb4ee6a4SAndroid Build Coastguard Worker tap2_name.as_bytes(),
88*bb4ee6a4SAndroid Build Coastguard Worker "100.115.92.25".parse().unwrap(),
89*bb4ee6a4SAndroid Build Coastguard Worker "255.255.255.252".parse().unwrap(),
90*bb4ee6a4SAndroid Build Coastguard Worker "a0:b0:c0:d0:e0:f2".parse().unwrap(),
91*bb4ee6a4SAndroid Build Coastguard Worker );
92*bb4ee6a4SAndroid Build Coastguard Worker
93*bb4ee6a4SAndroid Build Coastguard Worker // Check number of virtio-net devices after each hotplug.
94*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
95*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
96*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 0 },
97*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
98*bb4ee6a4SAndroid Build Coastguard Worker ));
99*bb4ee6a4SAndroid Build Coastguard Worker vm.hotplug_tap(tap1_name).unwrap();
100*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
101*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
102*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 1 },
103*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
104*bb4ee6a4SAndroid Build Coastguard Worker ));
105*bb4ee6a4SAndroid Build Coastguard Worker vm.hotplug_tap(tap2_name).unwrap();
106*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
107*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
108*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 2 },
109*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
110*bb4ee6a4SAndroid Build Coastguard Worker ));
111*bb4ee6a4SAndroid Build Coastguard Worker
112*bb4ee6a4SAndroid Build Coastguard Worker // Check number of devices after each removal.
113*bb4ee6a4SAndroid Build Coastguard Worker vm.remove_pci_device(1).unwrap();
114*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
115*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
116*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 1 },
117*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
118*bb4ee6a4SAndroid Build Coastguard Worker ));
119*bb4ee6a4SAndroid Build Coastguard Worker vm.remove_pci_device(2).unwrap();
120*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
121*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
122*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 0 },
123*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
124*bb4ee6a4SAndroid Build Coastguard Worker ));
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker drop(vm);
127*bb4ee6a4SAndroid Build Coastguard Worker Command::new("ip")
128*bb4ee6a4SAndroid Build Coastguard Worker .args(["link", "delete", tap1_name])
129*bb4ee6a4SAndroid Build Coastguard Worker .status()
130*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
131*bb4ee6a4SAndroid Build Coastguard Worker Command::new("ip")
132*bb4ee6a4SAndroid Build Coastguard Worker .args(["link", "delete", tap2_name])
133*bb4ee6a4SAndroid Build Coastguard Worker .status()
134*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
135*bb4ee6a4SAndroid Build Coastguard Worker }
136*bb4ee6a4SAndroid Build Coastguard Worker
137*bb4ee6a4SAndroid Build Coastguard Worker /// Checks hotplug works with two tap devices.
138*bb4ee6a4SAndroid Build Coastguard Worker #[test]
tap_hotplug_two()139*bb4ee6a4SAndroid Build Coastguard Worker fn tap_hotplug_two() {
140*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("tap_hotplug_two_impl");
141*bb4ee6a4SAndroid Build Coastguard Worker }
142*bb4ee6a4SAndroid Build Coastguard Worker
143*bb4ee6a4SAndroid Build Coastguard Worker /// Implementation for tap_hotplug_add_remove_add
144*bb4ee6a4SAndroid Build Coastguard Worker ///
145*bb4ee6a4SAndroid Build Coastguard Worker /// This test will fail by itself due to permission.
146*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by tap_hotplug_add_remove_add"]
147*bb4ee6a4SAndroid Build Coastguard Worker #[test]
tap_hotplug_add_remove_add_impl()148*bb4ee6a4SAndroid Build Coastguard Worker fn tap_hotplug_add_remove_add_impl() {
149*bb4ee6a4SAndroid Build Coastguard Worker let wait_timeout = Duration::from_secs(5);
150*bb4ee6a4SAndroid Build Coastguard Worker // Setup VM start parameter.
151*bb4ee6a4SAndroid Build Coastguard Worker let config = Config::new().extra_args(vec!["--pci-hotplug-slots".to_owned(), "1".to_owned()]);
152*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
153*bb4ee6a4SAndroid Build Coastguard Worker
154*bb4ee6a4SAndroid Build Coastguard Worker //Setup test tap. tap_name has to be distinct per test, or it may appear flaky (b/333090169).
155*bb4ee6a4SAndroid Build Coastguard Worker let tap_name = "test_tap3";
156*bb4ee6a4SAndroid Build Coastguard Worker setup_tap_device(
157*bb4ee6a4SAndroid Build Coastguard Worker tap_name.as_bytes(),
158*bb4ee6a4SAndroid Build Coastguard Worker "100.115.92.5".parse().unwrap(),
159*bb4ee6a4SAndroid Build Coastguard Worker "255.255.255.252".parse().unwrap(),
160*bb4ee6a4SAndroid Build Coastguard Worker "a0:b0:c0:d0:e0:f0".parse().unwrap(),
161*bb4ee6a4SAndroid Build Coastguard Worker );
162*bb4ee6a4SAndroid Build Coastguard Worker
163*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
164*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
165*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 0 },
166*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
167*bb4ee6a4SAndroid Build Coastguard Worker ));
168*bb4ee6a4SAndroid Build Coastguard Worker // Hotplug tap.
169*bb4ee6a4SAndroid Build Coastguard Worker vm.hotplug_tap(tap_name).unwrap();
170*bb4ee6a4SAndroid Build Coastguard Worker // Wait until virtio-net device appears in guest OS.
171*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
172*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
173*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 1 },
174*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
175*bb4ee6a4SAndroid Build Coastguard Worker ));
176*bb4ee6a4SAndroid Build Coastguard Worker
177*bb4ee6a4SAndroid Build Coastguard Worker // Remove hotplugged tap device.
178*bb4ee6a4SAndroid Build Coastguard Worker vm.remove_pci_device(1).unwrap();
179*bb4ee6a4SAndroid Build Coastguard Worker // Wait until virtio-net device disappears from guest OS.
180*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
181*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
182*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 0 },
183*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
184*bb4ee6a4SAndroid Build Coastguard Worker ));
185*bb4ee6a4SAndroid Build Coastguard Worker
186*bb4ee6a4SAndroid Build Coastguard Worker // Hotplug tap again.
187*bb4ee6a4SAndroid Build Coastguard Worker vm.hotplug_tap(tap_name).unwrap();
188*bb4ee6a4SAndroid Build Coastguard Worker // Wait until virtio-net device appears in guest OS.
189*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
190*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
191*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 1 },
192*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
193*bb4ee6a4SAndroid Build Coastguard Worker ));
194*bb4ee6a4SAndroid Build Coastguard Worker
195*bb4ee6a4SAndroid Build Coastguard Worker drop(vm);
196*bb4ee6a4SAndroid Build Coastguard Worker Command::new("ip")
197*bb4ee6a4SAndroid Build Coastguard Worker .args(["link", "delete", tap_name])
198*bb4ee6a4SAndroid Build Coastguard Worker .status()
199*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
200*bb4ee6a4SAndroid Build Coastguard Worker }
201*bb4ee6a4SAndroid Build Coastguard Worker
202*bb4ee6a4SAndroid Build Coastguard Worker /// Checks tap hotplug works with a device added, removed, then added again.
203*bb4ee6a4SAndroid Build Coastguard Worker #[test]
tap_hotplug_add_remove_add()204*bb4ee6a4SAndroid Build Coastguard Worker fn tap_hotplug_add_remove_add() {
205*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("tap_hotplug_add_remove_add_impl");
206*bb4ee6a4SAndroid Build Coastguard Worker }
207*bb4ee6a4SAndroid Build Coastguard Worker
208*bb4ee6a4SAndroid Build Coastguard Worker /// Implementation for tap_hotplug_add_remove_rapid_add
209*bb4ee6a4SAndroid Build Coastguard Worker ///
210*bb4ee6a4SAndroid Build Coastguard Worker /// This test will fail by itself due to permission.
211*bb4ee6a4SAndroid Build Coastguard Worker #[ignore = "Only to be called by tap_hotplug_add_remove_rapid_add"]
212*bb4ee6a4SAndroid Build Coastguard Worker #[test]
tap_hotplug_add_remove_rapid_add_impl()213*bb4ee6a4SAndroid Build Coastguard Worker fn tap_hotplug_add_remove_rapid_add_impl() {
214*bb4ee6a4SAndroid Build Coastguard Worker let wait_timeout = Duration::from_secs(5);
215*bb4ee6a4SAndroid Build Coastguard Worker // Setup VM start parameter.
216*bb4ee6a4SAndroid Build Coastguard Worker let config = Config::new().extra_args(vec!["--pci-hotplug-slots".to_owned(), "1".to_owned()]);
217*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
218*bb4ee6a4SAndroid Build Coastguard Worker
219*bb4ee6a4SAndroid Build Coastguard Worker //Setup test tap. tap_name has to be distinct per test, or it may appear flaky (b/333090169).
220*bb4ee6a4SAndroid Build Coastguard Worker let tap_name_a = "test_tap4";
221*bb4ee6a4SAndroid Build Coastguard Worker setup_tap_device(
222*bb4ee6a4SAndroid Build Coastguard Worker tap_name_a.as_bytes(),
223*bb4ee6a4SAndroid Build Coastguard Worker "100.115.92.9".parse().unwrap(),
224*bb4ee6a4SAndroid Build Coastguard Worker "255.255.255.252".parse().unwrap(),
225*bb4ee6a4SAndroid Build Coastguard Worker "a0:b0:c0:d0:e0:f0".parse().unwrap(),
226*bb4ee6a4SAndroid Build Coastguard Worker );
227*bb4ee6a4SAndroid Build Coastguard Worker
228*bb4ee6a4SAndroid Build Coastguard Worker let tap_name_b = "test_tap5";
229*bb4ee6a4SAndroid Build Coastguard Worker setup_tap_device(
230*bb4ee6a4SAndroid Build Coastguard Worker tap_name_b.as_bytes(),
231*bb4ee6a4SAndroid Build Coastguard Worker "100.115.92.1".parse().unwrap(),
232*bb4ee6a4SAndroid Build Coastguard Worker "255.255.255.252".parse().unwrap(),
233*bb4ee6a4SAndroid Build Coastguard Worker "a0:b0:c0:d0:e0:f0".parse().unwrap(),
234*bb4ee6a4SAndroid Build Coastguard Worker );
235*bb4ee6a4SAndroid Build Coastguard Worker
236*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
237*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
238*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 0 },
239*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
240*bb4ee6a4SAndroid Build Coastguard Worker ));
241*bb4ee6a4SAndroid Build Coastguard Worker // Hotplug tap.
242*bb4ee6a4SAndroid Build Coastguard Worker vm.hotplug_tap(tap_name_a).unwrap();
243*bb4ee6a4SAndroid Build Coastguard Worker // Wait until virtio-net device appears in guest OS.
244*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
245*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
246*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 1 },
247*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
248*bb4ee6a4SAndroid Build Coastguard Worker ));
249*bb4ee6a4SAndroid Build Coastguard Worker
250*bb4ee6a4SAndroid Build Coastguard Worker // Remove hotplugged tap device, then hotplug again without waiting for guest.
251*bb4ee6a4SAndroid Build Coastguard Worker vm.remove_pci_device(1).unwrap();
252*bb4ee6a4SAndroid Build Coastguard Worker vm.hotplug_tap(tap_name_b).unwrap();
253*bb4ee6a4SAndroid Build Coastguard Worker
254*bb4ee6a4SAndroid Build Coastguard Worker // Wait for a while that the guest likely noticed the removal.
255*bb4ee6a4SAndroid Build Coastguard Worker thread::sleep(Duration::from_millis(500));
256*bb4ee6a4SAndroid Build Coastguard Worker // Wait until virtio-net device reappears in guest OS. This assertion would fail if the device
257*bb4ee6a4SAndroid Build Coastguard Worker // added later is not recognized.
258*bb4ee6a4SAndroid Build Coastguard Worker assert!(poll_until_true(
259*bb4ee6a4SAndroid Build Coastguard Worker &mut vm,
260*bb4ee6a4SAndroid Build Coastguard Worker |vm| { count_virtio_net_devices(vm) == 1 },
261*bb4ee6a4SAndroid Build Coastguard Worker wait_timeout
262*bb4ee6a4SAndroid Build Coastguard Worker ));
263*bb4ee6a4SAndroid Build Coastguard Worker
264*bb4ee6a4SAndroid Build Coastguard Worker drop(vm);
265*bb4ee6a4SAndroid Build Coastguard Worker Command::new("ip")
266*bb4ee6a4SAndroid Build Coastguard Worker .args(["link", "delete", tap_name_a])
267*bb4ee6a4SAndroid Build Coastguard Worker .status()
268*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
269*bb4ee6a4SAndroid Build Coastguard Worker Command::new("ip")
270*bb4ee6a4SAndroid Build Coastguard Worker .args(["link", "delete", tap_name_b])
271*bb4ee6a4SAndroid Build Coastguard Worker .status()
272*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
273*bb4ee6a4SAndroid Build Coastguard Worker }
274*bb4ee6a4SAndroid Build Coastguard Worker
275*bb4ee6a4SAndroid Build Coastguard Worker /// Checks tap hotplug works with a device added, removed, then rapidly added again.
276*bb4ee6a4SAndroid Build Coastguard Worker #[test]
tap_hotplug_add_remove_rapid_add()277*bb4ee6a4SAndroid Build Coastguard Worker fn tap_hotplug_add_remove_rapid_add() {
278*bb4ee6a4SAndroid Build Coastguard Worker call_test_with_sudo("tap_hotplug_add_remove_rapid_add_impl");
279*bb4ee6a4SAndroid Build Coastguard Worker }
280