diff options
-rw-r--r-- | devices/src/virtio/net.rs | 324 | ||||
-rw-r--r-- | devices/src/virtio/vhost/net.rs | 2 | ||||
-rw-r--r-- | net_util/src/lib.rs | 111 | ||||
-rw-r--r-- | src/linux.rs | 2 | ||||
-rw-r--r-- | src/plugin/mod.rs | 2 |
5 files changed, 300 insertions, 141 deletions
diff --git a/devices/src/virtio/net.rs b/devices/src/virtio/net.rs index 44a39ab..0200daf 100644 --- a/devices/src/virtio/net.rs +++ b/devices/src/virtio/net.rs @@ -9,20 +9,23 @@ use std::net::Ipv4Addr; use std::os::raw::c_uint; use std::os::unix::io::{AsRawFd, RawFd}; use std::result; +use std::sync::Arc; use std::thread; -use data_model::{DataInit, Le64}; +use data_model::{DataInit, Le16, Le64}; use net_sys; use net_util::{Error as TapError, MacAddress, TapT}; use sys_util::Error as SysError; use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken, WatchingEvents}; use virtio_sys::virtio_net::{ virtio_net_hdr_v1, VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, - VIRTIO_NET_ERR, VIRTIO_NET_OK, + VIRTIO_NET_CTRL_MQ, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_OK, }; use virtio_sys::{vhost, virtio_net}; -use super::{DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_NET}; +use super::{ + copy_config, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_NET, +}; const QUEUE_SIZE: u16 = 256; const NUM_QUEUES: usize = 3; @@ -132,17 +135,27 @@ fn virtio_features_to_tap_offload(features: u64) -> c_uint { tap_offloads } +#[derive(Debug, Clone, Copy, Default)] +#[repr(C)] +struct VirtioNetConfig { + mac: [u8; 6], + status: Le16, + max_vq_pairs: Le16, + mtu: Le16, +} + +// Safe because it only has data and has no implicit padding. +unsafe impl DataInit for VirtioNetConfig {} + struct Worker<T: TapT> { - interrupt: Interrupt, + interrupt: Arc<Interrupt>, mem: GuestMemory, rx_queue: Queue, tx_queue: Queue, - ctrl_queue: Queue, + ctrl_queue: Option<Queue>, tap: T, - // TODO(smbarber): http://crbug.com/753630 - // Remove once MRG_RXBUF is supported and this variable is actually used. - #[allow(dead_code)] acked_features: u64, + vq_pairs: u16, kill_evt: EventFd, } @@ -240,7 +253,12 @@ where } fn process_ctrl(&mut self) -> Result<(), NetError> { - while let Some(desc_chain) = self.ctrl_queue.pop(&self.mem) { + let ctrl_queue = match self.ctrl_queue.as_mut() { + Some(queue) => queue, + None => return Ok(()), + }; + + while let Some(desc_chain) = ctrl_queue.pop(&self.mem) { let index = desc_chain.index; let mut reader = @@ -259,7 +277,7 @@ where ); let ack = VIRTIO_NET_ERR as u8; writer.write_all(&[ack]).map_err(NetError::WriteAck)?; - self.ctrl_queue.add_used(&self.mem, index, 0); + ctrl_queue.add_used(&self.mem, index, 0); continue; } let offloads: Le64 = reader.read_obj().map_err(NetError::ReadCtrlData)?; @@ -270,16 +288,34 @@ where let ack = VIRTIO_NET_OK as u8; writer.write_all(&[ack]).map_err(NetError::WriteAck)?; } + VIRTIO_NET_CTRL_MQ => { + if ctrl_hdr.cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET as u8 { + let pairs: Le16 = reader.read_obj().map_err(NetError::ReadCtrlData)?; + // Simple handle it now + if self.acked_features & 1 << virtio_net::VIRTIO_NET_F_MQ == 0 + || pairs.to_native() != self.vq_pairs + { + error!("Invalid VQ_PAIRS_SET cmd, driver request pairs: {}, device vq pairs: {}", + pairs.to_native(), self.vq_pairs); + let ack = VIRTIO_NET_ERR as u8; + writer.write_all(&[ack]).map_err(NetError::WriteAck)?; + ctrl_queue.add_used(&self.mem, index, 0); + continue; + } + let ack = VIRTIO_NET_OK as u8; + writer.write_all(&[ack]).map_err(NetError::WriteAck)?; + } + } _ => warn!( "unimplemented class for VIRTIO_NET_CTRL_GUEST_OFFLOADS: {}", ctrl_hdr.class ), } - self.ctrl_queue.add_used(&self.mem, index, 0); + ctrl_queue.add_used(&self.mem, index, 0); } - self.interrupt.signal_used_queue(self.ctrl_queue.vector); + self.interrupt.signal_used_queue(ctrl_queue.vector); Ok(()) } @@ -287,7 +323,7 @@ where &mut self, rx_queue_evt: EventFd, tx_queue_evt: EventFd, - ctrl_queue_evt: EventFd, + ctrl_queue_evt: Option<EventFd>, ) -> Result<(), NetError> { #[derive(PollToken)] enum Token { @@ -309,12 +345,20 @@ where (&self.tap, Token::RxTap), (&rx_queue_evt, Token::RxQueue), (&tx_queue_evt, Token::TxQueue), - (&ctrl_queue_evt, Token::CtrlQueue), - (self.interrupt.get_resample_evt(), Token::InterruptResample), (&self.kill_evt, Token::Kill), ]) .map_err(NetError::CreatePollContext)?; + if let Some(ctrl_evt) = &ctrl_queue_evt { + poll_ctx + .add(ctrl_evt, Token::CtrlQueue) + .map_err(NetError::CreatePollContext)?; + // Let CtrlQueue's thread handle InterruptResample also. + poll_ctx + .add(self.interrupt.get_resample_evt(), Token::InterruptResample) + .map_err(NetError::CreatePollContext)?; + } + let mut tap_polling_enabled = true; 'poll: loop { let events = poll_ctx.wait().map_err(NetError::PollError)?; @@ -350,8 +394,12 @@ where self.process_tx(); } Token::CtrlQueue => { - if let Err(e) = ctrl_queue_evt.read() { - error!("net: error reading ctrl queue EventFd: {}", e); + if let Some(ctrl_evt) = &ctrl_queue_evt { + if let Err(e) = ctrl_evt.read() { + error!("net: error reading ctrl queue EventFd: {}", e); + break 'poll; + } + } else { break 'poll; } if let Err(e) = self.process_ctrl() { @@ -374,10 +422,10 @@ where } pub struct Net<T: TapT> { - workers_kill_evt: Option<EventFd>, - kill_evt: EventFd, - worker_thread: Option<thread::JoinHandle<Worker<T>>>, - tap: Option<T>, + workers_kill_evt: Vec<EventFd>, + kill_evts: Vec<EventFd>, + worker_threads: Vec<thread::JoinHandle<Worker<T>>>, + taps: Vec<T>, avail_features: u64, acked_features: u64, } @@ -393,7 +441,9 @@ where netmask: Ipv4Addr, mac_addr: MacAddress, ) -> Result<Net<T>, NetError> { - let tap: T = T::new(true).map_err(NetError::TapOpen)?; + let vq_pairs = QUEUE_SIZES.len() as u16 / 2; + let multi_queue = if vq_pairs > 1 { true } else { false }; + let tap: T = T::new(true, multi_queue).map_err(NetError::TapOpen)?; tap.set_ip_addr(ip_addr).map_err(NetError::TapSetIp)?; tap.set_netmask(netmask).map_err(NetError::TapSetNetmask)?; tap.set_mac_address(mac_addr) @@ -401,18 +451,22 @@ where tap.enable().map_err(NetError::TapEnable)?; - Net::from(tap) + Net::from(tap, vq_pairs) } /// Creates a new virtio network device from a tap device that has already been /// configured. - pub fn from(tap: T) -> Result<Net<T>, NetError> { + pub fn from(tap: T, vq_pairs: u16) -> Result<Net<T>, NetError> { + let taps = tap.into_mq_taps(vq_pairs).map_err(NetError::TapOpen)?; + // This would also validate a tap created by Self::new(), but that's a good thing as it // would ensure that any changes in the creation procedure are matched in the validation. // Plus we still need to set the offload and vnet_hdr_size values. - validate_and_configure_tap(&tap)?; + for tap in &taps { + validate_and_configure_tap(tap, vq_pairs)?; + } - let avail_features = 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM + let mut avail_features = 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM | 1 << virtio_net::VIRTIO_NET_F_CSUM | 1 << virtio_net::VIRTIO_NET_F_CTRL_VQ | 1 << virtio_net::VIRTIO_NET_F_CTRL_GUEST_OFFLOADS @@ -422,27 +476,54 @@ where | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO | 1 << vhost::VIRTIO_F_VERSION_1; - let kill_evt = EventFd::new().map_err(NetError::CreateKillEventFd)?; + if vq_pairs > 1 { + avail_features |= 1 << virtio_net::VIRTIO_NET_F_MQ; + } + + let mut kill_evts: Vec<EventFd> = Vec::new(); + let mut workers_kill_evt: Vec<EventFd> = Vec::new(); + for _ in 0..taps.len() { + let kill_evt = EventFd::new().map_err(NetError::CreateKillEventFd)?; + let worker_kill_evt = kill_evt.try_clone().map_err(NetError::CloneKillEventFd)?; + kill_evts.push(kill_evt); + workers_kill_evt.push(worker_kill_evt); + } + Ok(Net { - workers_kill_evt: Some(kill_evt.try_clone().map_err(NetError::CloneKillEventFd)?), - kill_evt, - worker_thread: None, - tap: Some(tap), + workers_kill_evt, + kill_evts, + worker_threads: Vec::new(), + taps, avail_features, acked_features: 0u64, }) } + + fn build_config(&self) -> VirtioNetConfig { + let vq_pairs = QUEUE_SIZES.len() as u16 / 2; + + VirtioNetConfig { + max_vq_pairs: Le16::from(vq_pairs), + // Other field has meaningful value when the corresponding feature + // is enabled, but all these features aren't supported now. + // So set them to default. + ..Default::default() + } + } } // Ensure that the tap interface has the correct flags and sets the offload and VNET header size // to the appropriate values. -fn validate_and_configure_tap<T: TapT>(tap: &T) -> Result<(), NetError> { +fn validate_and_configure_tap<T: TapT>(tap: &T, vq_pairs: u16) -> Result<(), NetError> { let flags = tap.if_flags(); - let required_flags = [ + let mut required_flags = vec![ (net_sys::IFF_TAP, "IFF_TAP"), (net_sys::IFF_NO_PI, "IFF_NO_PI"), (net_sys::IFF_VNET_HDR, "IFF_VNET_HDR"), ]; + if vq_pairs > 1 { + required_flags.push((net_sys::IFF_MULTI_QUEUE, "IFF_MULTI_QUEUE")); + } let missing_flags = required_flags .iter() .filter_map( @@ -475,14 +556,20 @@ where T: TapT, { fn drop(&mut self) { - // Only kill the child if it claimed its eventfd. - if self.workers_kill_evt.is_none() { - // Ignore the result because there is nothing we can do about it. - let _ = self.kill_evt.write(1); + let len = self.kill_evts.len(); + for i in 0..len { + // Only kill the child if it claimed its eventfd. + if self.workers_kill_evt.get(i).is_none() { + if let Some(kill_evt) = self.kill_evts.get(i) { + // Ignore the result because there is nothing we can do about it. + let _ = kill_evt.write(1); + } + } } - if let Some(worker_thread) = self.worker_thread.take() { - let _ = worker_thread.join(); + let len = self.worker_threads.len(); + for _ in 0..len { + let _ = self.worker_threads.remove(0).join(); } } } @@ -494,14 +581,16 @@ where fn keep_fds(&self) -> Vec<RawFd> { let mut keep_fds = Vec::new(); - if let Some(tap) = &self.tap { + for tap in &self.taps { keep_fds.push(tap.as_raw_fd()); } - if let Some(workers_kill_evt) = &self.workers_kill_evt { - keep_fds.push(workers_kill_evt.as_raw_fd()); + for worker_kill_evt in &self.workers_kill_evt { + keep_fds.push(worker_kill_evt.as_raw_fd()); + } + for kill_evt in &self.kill_evts { + keep_fds.push(kill_evt.as_raw_fd()); } - keep_fds.push(self.kill_evt.as_raw_fd()); keep_fds } @@ -532,19 +621,21 @@ where self.acked_features |= v; // Set offload flags to match acked virtio features. - if let Err(e) = self - .tap - .as_ref() - .expect("missing tap in ack_features") - .set_offload(virtio_features_to_tap_offload(self.acked_features)) - { - warn!( - "net: failed to set tap offload to match acked features: {}", - e - ); + if let Some(tap) = self.taps.first() { + if let Err(e) = tap.set_offload(virtio_features_to_tap_offload(self.acked_features)) { + warn!( + "net: failed to set tap offload to match acked features: {}", + e + ); + } } } + fn read_config(&self, offset: u64, data: &mut [u8]) { + let config_space = self.build_config(); + copy_config(data, 0, config_space.as_slice(), offset); + } + fn activate( &mut self, mem: GuestMemory, @@ -557,70 +648,101 @@ where return; } - if let Some(tap) = self.tap.take() { - if let Some(kill_evt) = self.workers_kill_evt.take() { - let acked_features = self.acked_features; - let worker_result = - thread::Builder::new() - .name("virtio_net".to_string()) - .spawn(move || { - // First queue is rx, second is tx, third is ctrl. - let rx_queue = queues.remove(0); - let tx_queue = queues.remove(0); - let ctrl_queue = queues.remove(0); - let mut worker = Worker { - interrupt, - mem, - rx_queue, - tx_queue, - ctrl_queue, - tap, - acked_features, - kill_evt, - }; - let rx_queue_evt = queue_evts.remove(0); - let tx_queue_evt = queue_evts.remove(0); - let ctrl_queue_evt = queue_evts.remove(0); - let result = worker.run(rx_queue_evt, tx_queue_evt, ctrl_queue_evt); - if let Err(e) = result { - error!("net worker thread exited with error: {}", e); - } - worker - }); - - match worker_result { - Err(e) => { - error!("failed to spawn virtio_net worker: {}", e); - return; - } - Ok(join_handle) => { - self.worker_thread = Some(join_handle); + let vq_pairs = QUEUE_SIZES.len() / 2; + if self.taps.len() != vq_pairs { + error!("net: expected {} taps, got {}", vq_pairs, self.taps.len()); + return; + } + if self.workers_kill_evt.len() != vq_pairs { + error!( + "net: expected {} worker_kill_evt, got {}", + vq_pairs, + self.workers_kill_evt.len() + ); + return; + } + let interrupt_arc = Arc::new(interrupt); + for i in 0..vq_pairs { + let tap = self.taps.remove(0); + let acked_features = self.acked_features; + let interrupt = interrupt_arc.clone(); + let memory = mem.clone(); + let kill_evt = self.workers_kill_evt.remove(0); + // Queues alternate between rx0, tx0, rx1, tx1, ..., rxN, txN, ctrl. + let rx_queue = queues.remove(0); + let tx_queue = queues.remove(0); + let ctrl_queue = if i == 0 { + Some(queues.remove(queues.len() - 1)) + } else { + None + }; + let pairs = vq_pairs as u16; + let rx_queue_evt = queue_evts.remove(0); + let tx_queue_evt = queue_evts.remove(0); + let ctrl_queue_evt = if i == 0 { + Some(queue_evts.remove(queue_evts.len() - 1)) + } else { + None + }; + let worker_result = thread::Builder::new() + .name(format!("virtio_net worker {}", i)) + .spawn(move || { + let mut worker = Worker { + interrupt, + mem: memory, + rx_queue, + tx_queue, + ctrl_queue, + tap, + acked_features, + vq_pairs: pairs, + kill_evt, + }; + let result = worker.run(rx_queue_evt, tx_queue_evt, ctrl_queue_evt); + if let Err(e) = result { + error!("net worker thread exited with error: {}", e); } + worker + }); + + match worker_result { + Err(e) => { + error!("failed to spawn virtio_net worker: {}", e); + return; } + Ok(join_handle) => self.worker_threads.push(join_handle), } } } fn reset(&mut self) -> bool { - // Only kill the child if it claimed its eventfd. - if self.workers_kill_evt.is_none() && self.kill_evt.write(1).is_err() { - error!("{}: failed to notify the kill event", self.debug_label()); - return false; + let len = self.kill_evts.len(); + for i in 0..len { + // Only kill the child if it claimed its eventfd. + if self.workers_kill_evt.get(i).is_none() { + if let Some(kill_evt) = self.kill_evts.get(i) { + if kill_evt.write(1).is_err() { + error!("{}: failed to notify the kill event", self.debug_label()); + return false; + } + } + } } - if let Some(worker_thread) = self.worker_thread.take() { - match worker_thread.join() { + let len = self.worker_threads.len(); + for _ in 0..len { + match self.worker_threads.remove(0).join() { Err(_) => { error!("{}: failed to get back resources", self.debug_label()); return false; } Ok(worker) => { - self.tap = Some(worker.tap); - self.workers_kill_evt = Some(worker.kill_evt); - return true; + self.taps.push(worker.tap); + self.workers_kill_evt.push(worker.kill_evt); } } } - false + + return true; } } diff --git a/devices/src/virtio/vhost/net.rs b/devices/src/virtio/vhost/net.rs index 542423a..681cfe8 100644 --- a/devices/src/virtio/vhost/net.rs +++ b/devices/src/virtio/vhost/net.rs @@ -53,7 +53,7 @@ where ) -> Result<Net<T, U>> { let kill_evt = EventFd::new().map_err(Error::CreateKillEventFd)?; - let tap: T = T::new(true).map_err(Error::TapOpen)?; + let tap: T = T::new(true, false).map_err(Error::TapOpen)?; tap.set_ip_addr(ip_addr).map_err(Error::TapSetIp)?; tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?; tap.set_mac_address(mac_addr) diff --git a/net_util/src/lib.rs b/net_util/src/lib.rs index 0243552..a91a116 100644 --- a/net_util/src/lib.rs +++ b/net_util/src/lib.rs @@ -188,13 +188,54 @@ impl Tap { if_flags: ifreq.ifr_ifru.ifru_flags, }) } + + fn create_tap_with_ifreq(ifreq: &mut net_sys::ifreq) -> Result<Tap> { + // Open calls are safe because we give a constant nul-terminated + // string and verify the result. + let fd = unsafe { + libc::open( + b"/dev/net/tun\0".as_ptr() as *const c_char, + libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC, + ) + }; + if fd < 0 { + return Err(Error::OpenTun(SysError::last())); + } + + // We just checked that the fd is valid. + let tuntap = unsafe { File::from_raw_fd(fd) }; + // ioctl is safe since we call it with a valid tap fd and check the return + // value. + let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_sys::TUNSETIFF(), ifreq) }; + + if ret < 0 { + let error = SysError::last(); + + // In a non-root, test environment, we won't have permission to call this; allow + if !(cfg!(test) && error.errno() == EPERM) { + return Err(Error::CreateTap(error)); + } + } + + // Safe since only the name is accessed, and it's copied out. + Ok(Tap { + tap_file: tuntap, + if_name: unsafe { ifreq.ifr_ifrn.ifrn_name }, + if_flags: unsafe { ifreq.ifr_ifru.ifru_flags }, + }) + } } pub trait TapT: FileReadWriteVolatile + Read + Write + AsRawFd + Send + Sized { /// Create a new tap interface. Set the `vnet_hdr` flag to true to allow offloading on this tap, /// which will add an extra 12 byte virtio net header to incoming frames. Offloading cannot /// be used if `vnet_hdr` is false. - fn new(vnet_hdr: bool) -> Result<Self>; + /// set 'multi_vq' to ture, if tap have multi virt queue pairs + fn new(vnet_hdr: bool, multi_vq: bool) -> Result<Self>; + + /// Change the origin tap into multiqueue taps, this means create other taps based on the + /// origin tap. + fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>; /// Get the host-side IP address for the tap interface. fn ip_addr(&self) -> Result<net::Ipv4Addr>; @@ -230,22 +271,7 @@ pub trait TapT: FileReadWriteVolatile + Read + Write + AsRawFd + Send + Sized { } impl TapT for Tap { - fn new(vnet_hdr: bool) -> Result<Tap> { - // Open calls are safe because we give a constant nul-terminated - // string and verify the result. - let fd = unsafe { - libc::open( - b"/dev/net/tun\0".as_ptr() as *const c_char, - libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC, - ) - }; - if fd < 0 { - return Err(Error::OpenTun(SysError::last())); - } - - // We just checked that the fd is valid. - let tuntap = unsafe { File::from_raw_fd(fd) }; - + fn new(vnet_hdr: bool, multi_vq: bool) -> Result<Tap> { const TUNTAP_DEV_FORMAT: &[u8; 8usize] = b"vmtap%d\0"; // This is pretty messy because of the unions used by ifreq. Since we @@ -262,27 +288,34 @@ impl TapT for Tap { | net_sys::IFF_NO_PI | if vnet_hdr { net_sys::IFF_VNET_HDR } else { 0 }) as c_short; + if multi_vq { + ifreq.ifr_ifru.ifru_flags |= net_sys::IFF_MULTI_QUEUE as c_short; + } } - // ioctl is safe since we call it with a valid tap fd and check the return - // value. - let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_sys::TUNSETIFF(), &mut ifreq) }; + Tap::create_tap_with_ifreq(&mut ifreq) + } - if ret < 0 { - let error = SysError::last(); + fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Tap>> { + let mut taps: Vec<Tap> = Vec::new(); - // In a non-root, test environment, we won't have permission to call this; allow - if !(cfg!(test) && error.errno() == EPERM) { - return Err(Error::CreateTap(error)); - } + if vq_pairs <= 1 { + taps.push(self); + return Ok(taps); } - // Safe since only the name is accessed, and it's copied out. - Ok(Tap { - tap_file: tuntap, - if_name: unsafe { ifreq.ifr_ifrn.ifrn_name }, - if_flags: unsafe { ifreq.ifr_ifru.ifru_flags }, - }) + // Add other socket into the origin tap interface + for _ in 0..vq_pairs - 1 { + let mut ifreq = self.get_ifreq(); + let tap = Tap::create_tap_with_ifreq(&mut ifreq)?; + + tap.enable()?; + + taps.push(tap); + } + + taps.insert(0, self); + Ok(taps) } fn ip_addr(&self) -> Result<net::Ipv4Addr> { @@ -499,7 +532,7 @@ pub mod fakes { } impl TapT for FakeTap { - fn new(_: bool) -> Result<FakeTap> { + fn new(_: bool, _: bool) -> Result<FakeTap> { Ok(FakeTap { tap_file: OpenOptions::new() .read(true) @@ -510,6 +543,10 @@ pub mod fakes { }) } + fn into_mq_taps(self, _vq_pairs: u16) -> Result<Vec<FakeTap>> { + Ok(Vec::new()) + } + fn ip_addr(&self) -> Result<net::Ipv4Addr> { Ok(net::Ipv4Addr::new(1, 2, 3, 4)) } @@ -600,12 +637,12 @@ mod tests { #[test] fn tap_create() { - Tap::new(true).unwrap(); + Tap::new(true, false).unwrap(); } #[test] fn tap_configure() { - let tap = Tap::new(true).unwrap(); + let tap = Tap::new(true, false).unwrap(); let ip_addr: net::Ipv4Addr = "100.115.92.5".parse().unwrap(); let netmask: net::Ipv4Addr = "255.255.255.252".parse().unwrap(); let mac_addr: MacAddress = "a2:06:b9:3d:68:4d".parse().unwrap(); @@ -625,14 +662,14 @@ mod tests { #[ignore] fn root_only_tests() { // This line will fail to provide an initialized FD if the test is not run as root. - let tap = Tap::new(true).unwrap(); + let tap = Tap::new(true, false).unwrap(); tap.set_vnet_hdr_size(16).unwrap(); tap.set_offload(0).unwrap(); } #[test] fn tap_enable() { - let tap = Tap::new(true).unwrap(); + let tap = Tap::new(true, false).unwrap(); let ret = tap.enable(); assert_ok_or_perm_denied(ret); diff --git a/src/linux.rs b/src/linux.rs index 3370c1e..6eb1ef7 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -593,7 +593,7 @@ fn create_tap_net_device(cfg: &Config, tap_fd: RawFd) -> DeviceResult { .map_err(Error::CreateTapDevice)? }; - let dev = virtio::Net::from(tap).map_err(Error::NetDeviceNew)?; + let dev = virtio::Net::from(tap, 1).map_err(Error::NetDeviceNew)?; Ok(VirtioDeviceStub { dev: Box::new(dev), diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 1c7027f..ae7e19c 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -662,7 +662,7 @@ pub fn run_config(cfg: Config) -> Result<()> { if let Some(host_ip) = cfg.host_ip { if let Some(netmask) = cfg.netmask { if let Some(mac_address) = cfg.mac_address { - let tap = Tap::new(false).map_err(Error::TapOpen)?; + let tap = Tap::new(false, false).map_err(Error::TapOpen)?; tap.set_ip_addr(host_ip).map_err(Error::TapSetIp)?; tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?; tap.set_mac_address(mac_address) |