diff --git a/src/rust/catpowder/win/runtime.rs b/src/rust/catpowder/win/runtime.rs index e758dbc0b..a893fce17 100644 --- a/src/rust/catpowder/win/runtime.rs +++ b/src/rust/catpowder/win/runtime.rs @@ -44,6 +44,7 @@ struct CatpowderRuntimeInner { api: XdpApi, tx: TxRing, rx_rings: Vec, + vf_rx_rings : Vec, } //====================================================================================================================== // Implementations @@ -60,6 +61,7 @@ impl SharedCatpowderRuntime { /// Instantiates a new XDP runtime. pub fn new(config: &Config) -> Result { let ifindex: u32 = config.local_interface_index()?; + let vf_if_index: u32 = config.local_vf_interface_index()?; trace!("Creating XDP runtime."); let mut api: XdpApi = XdpApi::new()?; @@ -72,9 +74,16 @@ impl SharedCatpowderRuntime { for queueid in 0..queue_count { rx_rings.push(RxRing::new(&mut api, Self::RING_LENGTH, ifindex, queueid as u32)?); } - trace!("Created {} RX rings.", rx_rings.len()); + trace!("Created {} RX rings on interface {}", rx_rings.len(), ifindex); - Ok(Self(SharedObject::new(CatpowderRuntimeInner { api, tx, rx_rings }))) + let vf_queue_count = deduce_rss_settings(&mut api, vf_if_index)?; + let mut vf_rx_rings= Vec::with_capacity(vf_queue_count as usize); + for queueid in 0..vf_queue_count { + vf_rx_rings.push(RxRing::new(&mut api, Self::RING_LENGTH, vf_if_index, queueid as u32)?); + } + trace!("Created {} RX rings on interface {}.", vf_rx_rings.len(), vf_if_index); + + Ok(Self(SharedObject::new(CatpowderRuntimeInner { api, tx, rx_rings, vf_rx_rings }))) } } @@ -153,6 +162,25 @@ impl PhysicalLayer for SharedCatpowderRuntime { } } + for rx in self.0.borrow_mut().vf_rx_rings.iter_mut() { + if rx.reserve_rx(Self::RING_LENGTH, &mut idx) == Self::RING_LENGTH { + let xdp_buffer: XdpBuffer = rx.get_buffer(idx); + let dbuf: DemiBuffer = DemiBuffer::from_slice(&*xdp_buffer)?; + rx.release_rx(Self::RING_LENGTH); + + ret.push(dbuf); + + rx.reserve_rx_fill(Self::RING_LENGTH, &mut idx); + // NB for now there is only ever one element in the fill ring, so we don't have to + // change the ring contents. + rx.submit_rx_fill(Self::RING_LENGTH); + + if ret.is_full() { + break; + } + } + } + Ok(ret) } } diff --git a/src/rust/demikernel/config.rs b/src/rust/demikernel/config.rs index 38154cb02..23a6caee6 100644 --- a/src/rust/demikernel/config.rs +++ b/src/rust/demikernel/config.rs @@ -60,8 +60,15 @@ mod raw_socket_config { pub const SECTION_NAME: &str = "raw_socket"; #[cfg(target_os = "linux")] pub const LOCAL_INTERFACE_NAME: &str = "linux_interface_name"; + + // the primary interface index. this should be the virtualized interface for VMs. #[cfg(target_os = "windows")] pub const LOCAL_INTERFACE_INDEX: &str = "xdp_interface_index"; + + // N.B. hyper-V VMs can have both NetVSC and VF interfaces working in tandem, in which case + // we need to listen to the corresponding VF interface as well. + #[cfg(target_os = "windows")] + pub const LOCAL_VF_INTERFACE_INDEX: &str = "xdp_vf_interface_index"; } //====================================================================================================================== @@ -292,6 +299,16 @@ impl Config { } } + #[cfg(all(feature = "catpowder-libos", target_os = "windows"))] + pub fn local_vf_interface_index(&self) -> Result { + // Parse local MAC address. + if let Some(addr) = Self::get_typed_env_option(raw_socket_config::LOCAL_VF_INTERFACE_INDEX)? { + Ok(addr) + } else { + Self::get_int_option(self.get_raw_socket_config()?, raw_socket_config::LOCAL_VF_INTERFACE_INDEX) + } + } + #[cfg(feature = "catnip-libos")] /// DPDK Config: Reads the "DPDK EAL" parameter the underlying configuration file. pub fn eal_init_args(&self) -> Result, Fail> {