Skip to content

Commit b3d0e2d

Browse files
chantrafacebook-github-bot
authored andcommitted
[antlir2_vm][net] Add option to dump traffic to a pcap file
Summary: Traffic to/from a qemu netdev can be dumped to a pcap file using the option: ``` -object filter-dump,id=id,netdev=dev[,file=filename][,maxlen=len][,position=head|tail|id=<id>][,insert=behind|before] Dump the network traffic on netdev dev to the file specified by filename. At most len bytes (64k by default) per packet are stored. The file format is libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. ``` This diff adds the `dump_file` field to `VirtualNic` struct and a setter. When dump_file is `None`, no traffic is being dumped. When `Some(path)`, traffic is dumped to `path`. Test Plan: buck2 test and upcoming diffs Reviewed By: wujj123456 Differential Revision: D63498734 fbshipit-source-id: bbcdd602550dbd230418229ef8f8688c943b5f30
1 parent ee99f03 commit b3d0e2d

File tree

1 file changed

+69
-2
lines changed
  • antlir/antlir2/antlir2_vm/src

1 file changed

+69
-2
lines changed

antlir/antlir2/antlir2_vm/src/net.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::ffi::OsString;
1212
use std::net::Ipv6Addr;
1313
use std::ops::Index;
1414
use std::ops::IndexMut;
15+
use std::path::PathBuf;
1516
use std::process::Command;
1617

1718
use thiserror::Error;
@@ -27,6 +28,8 @@ pub(crate) struct VirtualNIC {
2728
id: usize,
2829
/// Max Combined Channels of the NIC. Multi-queue is disabled when set to 1
2930
max_combined_channels: usize,
31+
/// Dump interface traffic to this file. This is not supported for multi-queue NICs.
32+
dump_file: Option<PathBuf>,
3033
}
3134

3235
#[derive(Error, Debug)]
@@ -35,6 +38,8 @@ pub(crate) enum VirtualNICError {
3538
IPCmdExecError(#[from] std::io::Error),
3639
#[error("Error from command: `{0}` ")]
3740
IPCmdReturnError(String),
41+
#[error("Traffic is not dumpable: `{0}` ")]
42+
TrafficDumpingNotSupported(String),
3843
}
3944

4045
type Result<T> = std::result::Result<T, VirtualNICError>;
@@ -46,6 +51,7 @@ impl VirtualNIC {
4651
Self {
4752
id,
4853
max_combined_channels,
54+
dump_file: None,
4955
}
5056
}
5157

@@ -92,6 +98,18 @@ impl VirtualNIC {
9298
})
9399
}
94100

101+
/// Set the file to dump interface traffic to.
102+
/// Set to None to disable dumping traffic.
103+
pub(crate) fn try_dump_file(&mut self, path: Option<PathBuf>) -> Result<&mut Self> {
104+
if self.max_combined_channels > 1 {
105+
return Err(VirtualNICError::TrafficDumpingNotSupported(
106+
"Can not dump traffic for multi-queue NIC: https://fburl.com/dmblggwc".into(),
107+
));
108+
}
109+
self.dump_file = path;
110+
Ok(self)
111+
}
112+
95113
/// Host side IP address. It's fd00:<id>::1.
96114
fn host_ipv6_addr(&self) -> Ipv6Addr {
97115
let mut ip: u128 = 0xfd00 << (128 - 16);
@@ -116,7 +134,7 @@ impl VirtualNIC {
116134

117135
impl QemuDevice for VirtualNIC {
118136
fn qemu_args(&self) -> Vec<OsString> {
119-
[
137+
let mut vec: Vec<_> = [
120138
"-netdev",
121139
&format!(
122140
"tap,id={dev_id},ifname={dev_name},script=no,downscript=no,queues={queues}",
@@ -141,7 +159,24 @@ impl QemuDevice for VirtualNIC {
141159
]
142160
.iter()
143161
.map(|x| x.into())
144-
.collect()
162+
.collect();
163+
if let Some(path) = &self.dump_file {
164+
vec.extend(
165+
[
166+
"-object",
167+
&format!(
168+
"filter-dump,id=dump0,netdev={},file={}",
169+
self.dev_id(),
170+
path.to_string_lossy()
171+
),
172+
]
173+
.iter()
174+
.map(|x| x.into())
175+
.collect::<Vec<_>>(),
176+
);
177+
}
178+
179+
vec
145180
}
146181
}
147182

@@ -219,6 +254,38 @@ mod test {
219254
)
220255
}
221256

257+
#[test]
258+
fn test_qemu_args_with_dump_file() {
259+
let dump_file = PathBuf::from("/tmp/dump");
260+
let mut nic = VirtualNIC::new(0, 1);
261+
nic.try_dump_file(Some(dump_file.clone())).unwrap();
262+
263+
assert_eq!(
264+
nic.qemu_args().join(OsStr::new(" ")),
265+
format!(
266+
"-netdev tap,id=net0,ifname=vm0,script=no,downscript=no,queues=1 \
267+
-device virtio-net-pci,netdev=net0,mac=00:00:00:00:00:01,mq=off,vectors=4 \
268+
-object filter-dump,id=dump0,netdev=net0,file={}",
269+
dump_file.to_string_lossy()
270+
)
271+
.as_str()
272+
)
273+
}
274+
275+
#[test]
276+
// This test is to make sure that the dump file is not added to the qemu args when it's not supported (multi-queue nics)
277+
fn test_qemu_args_with_dump_file_not_supported() {
278+
let dump_file = PathBuf::from("/tmp/dump");
279+
let mut nic = VirtualNIC::new(0, 2);
280+
assert!(nic.try_dump_file(Some(dump_file.clone())).is_err());
281+
282+
assert_eq!(
283+
nic.qemu_args().join(OsStr::new(" ")),
284+
"-netdev tap,id=net0,ifname=vm0,script=no,downscript=no,queues=2 \
285+
-device virtio-net-pci,netdev=net0,mac=00:00:00:00:00:01,mq=on,vectors=6"
286+
)
287+
}
288+
222289
#[test]
223290
fn test_qemu_multiqueue_args() {
224291
assert_eq!(

0 commit comments

Comments
 (0)