1use alloc::{boxed::Box, string::String, vec, vec::Vec};
27use spin::{Mutex, RwLock};
28
29use crate::device::events::InterruptCapableDevice;
30use crate::device::{Device, DeviceType};
31use crate::drivers::virtio::features::VIRTIO_F_ANY_LAYOUT;
32use crate::drivers::virtio::features::VIRTIO_RING_F_INDIRECT_DESC;
33use crate::interrupt::InterruptId;
34use crate::network::config::apply_pending_ip_for_interface;
35use crate::network::ethernet_interface::EthernetNetworkInterface;
36use crate::network::get_network_manager;
37use crate::object::capability::{MemoryMappingOps, Selectable};
38use crate::{
39 device::network::{
40 DevicePacket, EthernetDevice, MacAddress, NetworkDevice, NetworkInterfaceConfig,
41 NetworkStats,
42 },
43 drivers::virtio::{
44 device::{Register, VirtioDevice},
45 queue::{DescriptorFlag, VirtQueue},
46 },
47 object::capability::ControlOps,
48};
49use core::mem;
50
51const VIRTIO_NET_F_CSUM: u32 = 0; const VIRTIO_NET_F_GUEST_CSUM: u32 = 1; const VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: u32 = 2; const VIRTIO_NET_F_MTU: u32 = 3; const VIRTIO_NET_F_MAC: u32 = 5; const VIRTIO_NET_F_GUEST_TSO4: u32 = 7; const VIRTIO_NET_F_GUEST_TSO6: u32 = 8; const VIRTIO_NET_F_GUEST_ECN: u32 = 9; const VIRTIO_NET_F_GUEST_UFO: u32 = 10; const VIRTIO_NET_F_HOST_TSO4: u32 = 11; const VIRTIO_NET_F_HOST_TSO6: u32 = 12; const VIRTIO_NET_F_HOST_ECN: u32 = 13; const VIRTIO_NET_F_HOST_UFO: u32 = 14; const VIRTIO_NET_F_MRG_RXBUF: u32 = 15; const VIRTIO_NET_F_STATUS: u32 = 16; const VIRTIO_NET_F_CTRL_VQ: u32 = 17; const VIRTIO_NET_F_CTRL_RX: u32 = 18; const VIRTIO_NET_F_CTRL_VLAN: u32 = 19; const VIRTIO_NET_F_GUEST_ANNOUNCE: u32 = 21; const VIRTIO_NET_F_MQ: u32 = 22; const VIRTIO_NET_F_CTRL_MAC_ADDR: u32 = 23; const VIRTIO_NET_S_LINK_UP: u16 = 1; const VIRTIO_NET_S_ANNOUNCE: u16 = 2; const DEFAULT_MTU: usize = 1500;
80
81#[repr(C)]
83pub struct VirtioNetConfig {
84 pub mac: [u8; 6], pub status: u16, pub max_virtqueue_pairs: u16, pub mtu: u16, }
89
90#[repr(C)]
92#[derive(Debug, Clone, Copy)]
93pub struct VirtioNetHdr {
94 pub flags: u8, pub gso_type: u8, pub hdr_len: u16, pub gso_size: u16, pub csum_start: u16, pub csum_offset: u16, pub num_buffers: u16, }
102
103#[repr(C)]
105#[derive(Debug, Clone, Copy)]
106pub struct VirtioNetHdrBasic {
107 pub flags: u8, pub gso_type: u8, pub hdr_len: u16, pub gso_size: u16, pub csum_start: u16, pub csum_offset: u16, }
114
115impl VirtioNetHdr {
116 pub fn new() -> Self {
118 Self {
119 flags: 0,
120 gso_type: 0,
121 hdr_len: 0,
122 gso_size: 0,
123 csum_start: 0,
124 csum_offset: 0,
125 num_buffers: 0,
126 }
127 }
128}
129
130impl VirtioNetHdrBasic {
131 pub fn new() -> Self {
133 Self {
134 flags: 0,
135 gso_type: 0,
136 hdr_len: 0,
137 gso_size: 0,
138 csum_start: 0,
139 csum_offset: 0,
140 }
141 }
142}
143
144pub struct VirtioNetDevice {
146 base_addr: usize,
147 virtqueues: Mutex<[VirtQueue<'static>; 2]>, config: RwLock<Option<NetworkInterfaceConfig>>,
149 features: RwLock<u32>,
150 stats: Mutex<NetworkStats>,
151 initialized: Mutex<bool>,
152 rx_buffers: Mutex<Vec<Box<[u8]>>>,
153 interrupt_id: Mutex<Option<InterruptId>>,
154 interface_name: Mutex<Option<String>>,
155}
156
157impl VirtioNetDevice {
158 pub fn new(base_addr: usize) -> Self {
168 let mut device = Self {
169 base_addr,
170 virtqueues: Mutex::new([VirtQueue::new(32), VirtQueue::new(32)]), config: RwLock::new(None),
172 features: RwLock::new(0),
173 stats: Mutex::new(NetworkStats::default()),
174 initialized: Mutex::new(false),
175 rx_buffers: Mutex::new(Vec::new()),
176 interrupt_id: Mutex::new(None),
177 interface_name: Mutex::new(None),
178 };
179
180 let negotiated_features = match device.init() {
182 Ok(features) => features,
183 Err(e) => panic!("Failed to initialize VirtIO Network Device: {}", e),
184 };
185
186 device.read_device_config(negotiated_features);
188
189 if let Err(e) = device.init_network() {
194 crate::early_println!(
195 "[virtio-net] Warning: failed to initialize RX buffers early: {}",
196 e
197 );
198 }
199
200 device
201 }
202
203 pub fn register_interface(self: &alloc::sync::Arc<Self>, name: &str) {
204 let manager = get_network_manager();
205 let interface = alloc::sync::Arc::new(EthernetNetworkInterface::new(name, self.clone()));
206
207 match manager.register_interface(name, interface.clone()) {
208 Ok(()) => {
209 *self.interface_name.lock() = Some(alloc::string::String::from(name));
210
211 if let Some(eth_layer) =
213 crate::network::protocol_stack::get_network_manager().get_layer("ethernet")
214 {
215 if let Some(eth) = eth_layer
216 .as_any()
217 .downcast_ref::<crate::network::ethernet::EthernetLayer>()
218 {
219 if let Ok(mac) = self.get_mac_address() {
220 eth.register_interface(name, mac, interface.clone());
221 crate::early_println!(
222 "[virtio-net] Registered {} with EthernetLayer (MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X})",
223 name,
224 mac.as_bytes()[0],
225 mac.as_bytes()[1],
226 mac.as_bytes()[2],
227 mac.as_bytes()[3],
228 mac.as_bytes()[4],
229 mac.as_bytes()[5]
230 );
231 }
232 }
233 } else {
234 crate::early_println!(
235 "[virtio-net] Warning: EthernetLayer not initialized, {} not registered with protocol stack",
236 name
237 );
238 }
239
240 apply_pending_ip_for_interface(name);
241 crate::early_println!("[virtio-net] Registered interface {}", name);
242 }
243 Err(e) => {
244 crate::early_println!("[virtio-net] Failed to register interface {}: {}", name, e);
245 }
246 }
247 }
248
249 fn read_device_config(&mut self, negotiated_features: u32) {
251 *self.features.write() = negotiated_features;
253
254 #[cfg(test)]
256 {
257 use crate::{drivers::virtio::device::Register, early_println};
258 let device_features = self.read32_register(Register::DeviceFeatures);
260 early_println!(
261 "[virtio-net] Device offers features: 0x{:x}",
262 device_features
263 );
264 early_println!(
265 "[virtio-net] Negotiated features: 0x{:x}",
266 negotiated_features
267 );
268 }
269
270 let mut mac_addr = [0u8; 6];
272 if negotiated_features & (1 << VIRTIO_NET_F_MAC) != 0 {
273 for i in 0..6 {
274 mac_addr[i] = self.read_config::<u8>(i);
275 }
276 } else {
277 mac_addr = [0x52, 0x54, 0x00, 0x12, 0x34, 0x56];
279 }
280
281 let mtu = if negotiated_features & (1 << VIRTIO_NET_F_MTU) != 0 {
283 self.read_config::<u16>(12) as usize } else {
285 DEFAULT_MTU
286 };
287
288 let mac = MacAddress::new(mac_addr);
290 let config = NetworkInterfaceConfig::new(mac, mtu, "virtio-net");
291 *self.config.write() = Some(config);
292 }
293
294 fn get_header_size(&self) -> usize {
296 mem::size_of::<VirtioNetHdrBasic>()
298 }
299
300 fn setup_rx_buffers(&self) -> Result<(), &'static str> {
302 let mut virtqueues = self.virtqueues.lock();
303 let rx_queue = &mut virtqueues[0]; let buffer_count = 16; for _ in 0..buffer_count {
309 let hdr_size = self.get_header_size(); let packet_size = 1514; let total_size = hdr_size + packet_size;
312
313 let buffer = vec![0u8; total_size];
315 let buffer_box = buffer.into_boxed_slice();
316 let buffer_ptr = Box::into_raw(buffer_box);
317
318 let desc_idx = rx_queue
320 .alloc_desc()
321 .ok_or("Failed to allocate RX descriptor")?;
322
323 let buffer_phys = crate::vm::get_kernel_vm_manager()
325 .translate_vaddr(buffer_ptr as *mut u8 as usize)
326 .ok_or("Failed to translate RX buffer vaddr")?;
327 rx_queue.desc[desc_idx].addr = buffer_phys as u64;
328 rx_queue.desc[desc_idx].len = total_size as u32;
329 rx_queue.desc[desc_idx].flags = DescriptorFlag::Write as u16; rx_queue.desc[desc_idx].next = 0; if let Err(e) = rx_queue.push(desc_idx) {
334 rx_queue.free_desc(desc_idx);
335 unsafe {
336 drop(Box::from_raw(buffer_ptr));
337 }
338 return Err(e);
339 }
340
341 self.rx_buffers
343 .lock()
344 .push(unsafe { Box::from_raw(buffer_ptr) });
345 }
346
347 unsafe {
349 core::ptr::write_volatile(rx_queue.avail.flags, 0);
350 core::ptr::write_volatile(rx_queue.used.flags, 0);
351 }
352 self.notify(0); Ok(())
355 }
356
357 fn transmit_packet(&self, packet: &DevicePacket) -> Result<(), &'static str> {
359 let hdr_size = mem::size_of::<VirtioNetHdrBasic>();
361 let total_size = hdr_size + packet.len;
362
363 crate::early_println!("[virtio-net] TX: payload={} bytes", packet.len);
364
365 let mut combined_buffer = vec![0u8; total_size];
367
368 let header = VirtioNetHdrBasic::new();
370 unsafe {
371 let header_bytes = core::slice::from_raw_parts(
372 &header as *const VirtioNetHdrBasic as *const u8,
373 hdr_size,
374 );
375 combined_buffer[..hdr_size].copy_from_slice(header_bytes);
376 }
377
378 combined_buffer[hdr_size..].copy_from_slice(&packet.data[..packet.len]);
380
381 let buffer_box = combined_buffer.into_boxed_slice();
383 let buffer_ptr = Box::into_raw(buffer_box);
384
385 let result = {
386 let mut virtqueues = self.virtqueues.lock();
387 let tx_queue = &mut virtqueues[1]; let desc_idx = tx_queue
391 .alloc_desc()
392 .ok_or("Failed to allocate TX descriptor")?;
393
394 let buffer_phys = crate::vm::get_kernel_vm_manager()
396 .translate_vaddr(buffer_ptr as *mut u8 as usize)
397 .ok_or("Failed to translate TX buffer vaddr")?;
398 tx_queue.desc[desc_idx].addr = buffer_phys as u64;
399 tx_queue.desc[desc_idx].len = total_size as u32;
400 tx_queue.desc[desc_idx].flags = 0; tx_queue.desc[desc_idx].next = 0; if let Err(e) = tx_queue.push(desc_idx) {
405 tx_queue.free_desc(desc_idx);
406 return Err(e);
407 }
408
409 self.notify(1); while tx_queue.is_busy() {}
414
415 let result = match tx_queue.pop() {
417 Some(_completed_desc) => Ok(()),
418 None => {
419 tx_queue.free_desc(desc_idx);
420 Err("No TX completion")
421 }
422 };
423
424 tx_queue.free_desc(desc_idx);
426
427 result
428 };
429
430 unsafe {
432 drop(Box::from_raw(buffer_ptr));
433 }
434
435 if result.is_ok() {
437 let mut stats = self.stats.lock();
438 stats.tx_packets += 1;
439 stats.tx_bytes += packet.len as u64;
440 }
441
442 result
443 }
444
445 fn process_received_packets(&self) -> Result<Vec<DevicePacket>, &'static str> {
447 let mut packets = Vec::new();
448 let mut virtqueues = self.virtqueues.lock();
449 let rx_queue = &mut virtqueues[0]; let mut buffers_recycled = 0usize;
452
453 while let Some((desc_idx, used_len)) = rx_queue.pop_used() {
455 let buffer_addr = rx_queue.desc[desc_idx].addr as *mut u8;
456 let buffer_len = rx_queue.desc[desc_idx].len as usize;
457 let used_len = core::cmp::min(used_len as usize, buffer_len);
458
459 unsafe {
460 let hdr_size = self.get_header_size();
461 if used_len > 0 {
462 let frame_offset = if used_len >= hdr_size { hdr_size } else { 0 };
463 let packet_data_ptr = buffer_addr.add(frame_offset);
464 let packet_len = used_len.saturating_sub(frame_offset);
465
466 crate::early_println!(
467 "[virtio-net] RX: used_len={} payload={} bytes",
468 used_len,
469 packet_len
470 );
471
472 let packet_data = core::slice::from_raw_parts(packet_data_ptr, packet_len);
473 let packet = DevicePacket::with_data(packet_data.to_vec());
474 packets.push(packet);
475 }
476 }
477
478 rx_queue.desc[desc_idx].flags = DescriptorFlag::Write as u16;
479 if let Err(_) = rx_queue.push(desc_idx) {
480 rx_queue.free_desc(desc_idx);
481 } else {
482 buffers_recycled += 1;
483 }
484 }
485
486 if buffers_recycled > 0 {
488 unsafe {
489 core::ptr::write_volatile(rx_queue.avail.flags, 0);
490 core::ptr::write_volatile(rx_queue.used.flags, 0);
491 }
492 self.notify(0); }
494
495 if !packets.is_empty() {
497 let mut stats = self.stats.lock();
498 stats.rx_packets += packets.len() as u64;
499 stats.rx_bytes += packets.iter().map(|p| p.len as u64).sum::<u64>();
500 }
501
502 Ok(packets)
503 }
504
505 fn check_link_status(&self) -> bool {
507 let features = *self.features.read();
508 if features & (1 << VIRTIO_NET_F_STATUS) != 0 {
509 let status = self.read_config::<u16>(6); (status & VIRTIO_NET_S_LINK_UP) != 0
512 } else {
513 true
515 }
516 }
517
518 pub fn enable_interrupts(&self, interrupt_id: InterruptId) -> Result<(), &'static str> {
520 *self.interrupt_id.lock() = Some(interrupt_id);
521
522 let isr = self.read32_register(Register::InterruptStatus);
523 if isr != 0 {
524 self.write32_register(Register::InterruptAck, isr & 0x03);
525 }
526
527 crate::interrupt::InterruptManager::with_manager(|mgr| {
528 mgr.enable_external_interrupt(interrupt_id, 0)
529 })
530 .map_err(|_| "Failed to enable interrupt in controller")?;
531
532 Ok(())
533 }
534
535 pub fn set_interface_name(&self, name: &str) {
537 *self.interface_name.lock() = Some(String::from(name));
538 }
539}
540
541impl MemoryMappingOps for VirtioNetDevice {
542 fn get_mapping_info(
543 &self,
544 _offset: usize,
545 _length: usize,
546 ) -> Result<(usize, usize, bool), &'static str> {
547 Err("Memory mapping not supported by VirtIO network device")
548 }
549
550 fn on_mapped(&self, _vaddr: usize, _paddr: usize, _length: usize, _offset: usize) {
551 }
553
554 fn on_unmapped(&self, _vaddr: usize, _length: usize) {
555 }
557
558 fn supports_mmap(&self) -> bool {
559 false
560 }
561}
562
563impl Device for VirtioNetDevice {
564 fn device_type(&self) -> DeviceType {
565 DeviceType::Network
566 }
567
568 fn name(&self) -> &'static str {
569 "virtio-net"
570 }
571
572 fn as_any(&self) -> &dyn core::any::Any {
573 self
574 }
575
576 fn as_any_mut(&mut self) -> &mut dyn core::any::Any {
577 self
578 }
579
580 fn as_network_device(&self) -> Option<&dyn crate::device::network::NetworkDevice> {
581 Some(self)
582 }
583}
584
585impl ControlOps for VirtioNetDevice {
586 fn control(&self, _command: u32, _arg: usize) -> Result<i32, &'static str> {
588 Err("Control operations not supported")
589 }
590}
591
592impl InterruptCapableDevice for VirtioNetDevice {
593 fn handle_interrupt(&self) -> crate::interrupt::InterruptResult<()> {
594 let isr = self.read32_register(Register::InterruptStatus);
595 if isr == 0 {
596 return Ok(());
597 }
598 crate::early_println!("[virtio-net] Interrupt received, ISR=0x{:x}", isr);
599 self.write32_register(Register::InterruptAck, isr & 0x03);
600
601 loop {
602 let packets = self.process_received_packets().unwrap_or_default();
603 crate::early_println!("[virtio-net] Processed {} packets", packets.len());
604 if packets.is_empty() {
605 break;
606 }
607
608 let interface_name = self.interface_name.lock().clone();
609 crate::early_println!("[virtio-net] Interface name: {:?}", interface_name);
610 if let Some(name) = interface_name {
611 crate::early_println!(
612 "[virtio-net] Forwarding {} packets to interface {}",
613 packets.len(),
614 name
615 );
616 let manager = crate::network::get_network_manager();
617 let mut inbound = 0usize;
618 for (i, packet) in packets.iter().enumerate() {
619 crate::early_println!("[virtio-net] Packet {}: {} bytes", i, packet.len);
620 if packet.len >= 14 {
621 let eth_type = u16::from_be_bytes([packet.data[12], packet.data[13]]);
622 crate::early_println!("[virtio-net] EtherType: 0x{:04X}", eth_type);
623 if eth_type == 0x0800 {
624 inbound += 1;
625 }
626 }
627 manager.handle_received_packet(&name, &packet);
628 }
629 crate::early_println!("[virtio-net] Forwarded IPv4 packets: {}", inbound);
630 } else {
631 crate::early_println!("[virtio-net] No interface name set!");
632 }
633 }
634
635 Ok(())
636 }
637
638 fn interrupt_id(&self) -> Option<InterruptId> {
639 self.interrupt_id.lock().clone()
640 }
641}
642
643impl VirtioDevice for VirtioNetDevice {
644 fn get_base_addr(&self) -> usize {
645 self.base_addr
646 }
647
648 fn get_virtqueue_count(&self) -> usize {
649 2 }
651
652 fn get_virtqueue_size(&self, queue_idx: usize) -> usize {
653 if queue_idx >= 2 {
654 panic!(
655 "Invalid queue index for VirtIO network device: {}",
656 queue_idx
657 );
658 }
659
660 let virtqueues = self.virtqueues.lock();
661 virtqueues[queue_idx].get_queue_size()
662 }
663
664 fn get_supported_features(&self, device_features: u32) -> u32 {
665 #[cfg(test)]
667 {
668 use crate::early_println;
669 early_println!(
670 "[virtio-net] Analyzing device features: 0x{:x}",
671 device_features
672 );
673 if device_features & (1 << VIRTIO_NET_F_MAC) != 0 {
674 early_println!(
675 "[virtio-net] Device supports MAC (bit {})",
676 VIRTIO_NET_F_MAC
677 );
678 }
679 if device_features & (1 << VIRTIO_NET_F_STATUS) != 0 {
680 early_println!(
681 "[virtio-net] Device supports STATUS (bit {})",
682 VIRTIO_NET_F_STATUS
683 );
684 }
685 if device_features & (1 << VIRTIO_NET_F_MTU) != 0 {
686 early_println!(
687 "[virtio-net] Device supports MTU (bit {})",
688 VIRTIO_NET_F_MTU
689 );
690 }
691 }
692
693 let mut result = device_features
696 & (1 << VIRTIO_NET_F_STATUS
697 | 1 << VIRTIO_NET_F_MAC
698 | 1 << VIRTIO_NET_F_MTU
699 | 1 << VIRTIO_F_ANY_LAYOUT);
700
701 if self.allow_ring_features() {
702 result |= device_features & (1 << VIRTIO_RING_F_INDIRECT_DESC);
704 }
705
706 #[cfg(test)]
707 {
708 use crate::early_println;
709 early_println!("[virtio-net] Using all device features: 0x{:x}", result);
710 }
711
712 result
713 }
714
715 fn get_queue_desc_addr(&self, queue_idx: usize) -> Option<u64> {
716 if queue_idx >= 2 {
717 return None;
718 }
719
720 let virtqueues = self.virtqueues.lock();
721 Some(virtqueues[queue_idx].get_raw_ptr() as u64)
722 }
723
724 fn get_queue_driver_addr(&self, queue_idx: usize) -> Option<u64> {
725 if queue_idx >= 2 {
726 return None;
727 }
728
729 let virtqueues = self.virtqueues.lock();
730 Some(virtqueues[queue_idx].avail.flags as *const _ as u64)
731 }
732
733 fn get_queue_device_addr(&self, queue_idx: usize) -> Option<u64> {
734 if queue_idx >= 2 {
735 return None;
736 }
737
738 let virtqueues = self.virtqueues.lock();
739 Some(virtqueues[queue_idx].used.flags as *const _ as u64)
740 }
741}
742
743impl Selectable for VirtioNetDevice {
744 fn wait_until_ready(
745 &self,
746 _interest: crate::object::capability::selectable::ReadyInterest,
747 _trapframe: &mut crate::arch::Trapframe,
748 _timeout_ticks: Option<u64>,
749 ) -> crate::object::capability::selectable::SelectWaitOutcome {
750 crate::object::capability::selectable::SelectWaitOutcome::Ready
751 }
752}
753
754impl NetworkDevice for VirtioNetDevice {
755 fn get_interface_name(&self) -> &'static str {
756 "virtio-net"
757 }
758
759 fn get_mac_address(&self) -> Result<MacAddress, &'static str> {
760 self.config
761 .read()
762 .as_ref()
763 .map(|config| config.mac_address)
764 .ok_or("Device not configured")
765 }
766
767 fn get_mtu(&self) -> Result<usize, &'static str> {
768 self.config
769 .read()
770 .as_ref()
771 .map(|config| config.mtu)
772 .ok_or("Device not configured")
773 }
774
775 fn get_interface_config(&self) -> Result<NetworkInterfaceConfig, &'static str> {
776 self.config.read().clone().ok_or("Device not configured")
777 }
778
779 fn send_packet(&self, packet: DevicePacket) -> Result<(), &'static str> {
780 if !self.is_link_up() {
781 return Err("Link is down");
782 }
783
784 self.transmit_packet(&packet)
785 }
786
787 fn receive_packets(&self) -> Result<Vec<DevicePacket>, &'static str> {
788 if !self.is_link_up() {
789 return Ok(Vec::new());
790 }
791
792 self.process_received_packets()
793 }
794
795 fn set_promiscuous_mode(&self, _enabled: bool) -> Result<(), &'static str> {
796 Ok(())
799 }
800
801 fn init_network(&mut self) -> Result<(), &'static str> {
802 {
803 let mut initialized = self.initialized.lock();
804 if *initialized {
805 return Ok(());
806 }
807 *initialized = true;
808 }
809
810 self.setup_rx_buffers()?;
812
813 Ok(())
814 }
815
816 fn is_link_up(&self) -> bool {
817 self.check_link_status()
818 }
819
820 fn get_stats(&self) -> NetworkStats {
821 self.stats.lock().clone()
822 }
823}
824
825impl EthernetDevice for VirtioNetDevice {
826 fn mac_address(&self) -> Result<MacAddress, &'static str> {
827 self.get_mac_address()
828 }
829}
830
831#[cfg(all(test, target_arch = "riscv64"))]
832mod tests {
833 use super::*;
834 use alloc::vec;
835
836 #[test_case]
837 fn test_virtio_net_device_creation() {
838 let device = VirtioNetDevice::new(0x10003000);
839 assert_eq!(device.get_base_addr(), 0x10003000);
840 assert_eq!(device.get_virtqueue_count(), 2);
841 assert_eq!(device.device_type(), DeviceType::Network);
842 assert_eq!(device.name(), "virtio-net");
843 assert_eq!(device.get_interface_name(), "virtio-net");
844 }
845
846 #[test_case]
847 fn test_virtio_net_header() {
848 let hdr = VirtioNetHdr::new();
849 assert_eq!(hdr.flags, 0);
850 assert_eq!(hdr.gso_type, 0);
851 assert_eq!(hdr.hdr_len, 0);
852 assert_eq!(hdr.gso_size, 0);
853 assert_eq!(hdr.csum_start, 0);
854 assert_eq!(hdr.csum_offset, 0);
855 assert_eq!(hdr.num_buffers, 0);
856 }
857
858 #[test_case]
859 fn test_virtio_net_device_config() {
860 let device = VirtioNetDevice::new(0x10003000);
861
862 assert!(device.get_mac_address().is_ok());
864 assert!(device.get_mtu().is_ok());
865 assert!(device.get_interface_config().is_ok());
866
867 let config = device.get_interface_config().unwrap();
868 assert_eq!(config.name, "virtio-net");
869 assert!(config.mtu > 0);
870 }
871
872 #[test_case]
873 fn test_virtio_net_initialization() {
874 let mut device = VirtioNetDevice::new(0x10003000);
875
876 assert!(device.init_network().is_ok());
878
879 assert!(device.init_network().is_ok());
881 }
882
883 #[test_case]
884 fn test_virtio_net_link_status() {
885 let device = VirtioNetDevice::new(0x10003000);
886
887 let _link_up = device.is_link_up();
890 }
892
893 #[test_case]
894 fn test_virtio_net_statistics() {
895 let mut device = VirtioNetDevice::new(0x10003000);
896 device.init_network().unwrap();
897
898 let initial_stats = device.get_stats();
899 assert_eq!(initial_stats.tx_packets, 0);
900 assert_eq!(initial_stats.tx_bytes, 0);
901 assert_eq!(initial_stats.rx_packets, 0);
902 assert_eq!(initial_stats.rx_bytes, 0);
903
904 if device.is_link_up() {
906 for i in 0..3 {
907 let data = vec![i; (i + 1) as usize];
908 let packet = DevicePacket::with_data(data);
909 device.send_packet(packet).unwrap();
910 }
911
912 let stats = device.get_stats();
913 assert_eq!(stats.tx_packets, 3);
914 assert_eq!(stats.tx_bytes, 1 + 2 + 3); }
916 }
917
918 #[test_case]
919 fn test_virtio_net_promiscuous_mode() {
920 let device = VirtioNetDevice::new(0x10003000);
921
922 assert!(device.set_promiscuous_mode(true).is_ok());
924 assert!(device.set_promiscuous_mode(false).is_ok());
925 }
926
927 #[test_case]
928 fn test_virtio_net_tx_functionality() {
929 let device = VirtioNetDevice::new(0x10003000);
930
931 let test_data = vec![0x45, 0x00, 0x00, 0x3c]; let packet = DevicePacket::with_data(test_data);
934
935 let result = device.transmit_packet(&packet);
937 match result {
940 Ok(_) => {
941 crate::early_println!("[virtio-net test] TX completed successfully");
943 }
944 Err(e) => {
945 crate::early_println!("[virtio-net test] TX result: {}", e);
947 }
948 }
949 }
950
951 #[test_case]
952 fn test_virtio_net_tx_with_multiple_packets() {
953 let device = VirtioNetDevice::new(0x10003000);
954
955 for i in 0..3 {
957 let mut test_data = vec![0x45, 0x00, 0x00, 0x3c];
958 test_data.push(i as u8); let packet = DevicePacket::with_data(test_data);
960
961 let result = device.transmit_packet(&packet);
962 crate::early_println!(
963 "[virtio-net test] Packet {} TX result: {:?}",
964 i,
965 result.is_ok()
966 );
967 }
968 }
969
970 #[test_case]
971 fn test_virtio_net_multiple_devices() {
972 let device1 = VirtioNetDevice::new(0x10003000); let device2 = VirtioNetDevice::new(0x10004000); let device3 = VirtioNetDevice::new(0x10005000); assert_eq!(device1.get_base_addr(), 0x10003000);
979 assert_eq!(device2.get_base_addr(), 0x10004000);
980 assert_eq!(device3.get_base_addr(), 0x10005000);
981
982 assert!(device1.get_mac_address().is_ok());
984 assert!(device2.get_mac_address().is_ok());
985 assert!(device3.get_mac_address().is_ok());
986
987 crate::early_println!("[virtio-net test] Multiple devices created successfully");
988
989 let test_data = vec![0x45, 0x00, 0x00, 0x3c];
991 let packet = DevicePacket::with_data(test_data);
992
993 let _result1 = device1.transmit_packet(&packet);
994 let _result2 = device2.transmit_packet(&packet);
995 let _result3 = device3.transmit_packet(&packet);
996
997 crate::early_println!("[virtio-net test] Transmitted packets on all 3 devices");
998 }
999
1000 #[test_case]
1001 fn test_virtio_net_bidirectional_hub_communication() {
1002 let device_net1 = VirtioNetDevice::new(0x10004000); let device_net2 = VirtioNetDevice::new(0x10005000); crate::early_println!("[virtio-net test] Testing bidirectional hub communication");
1008 crate::early_println!(
1009 "[virtio-net test] Device net1: {:#x}, Device net2: {:#x}",
1010 device_net1.get_base_addr(),
1011 device_net2.get_base_addr()
1012 );
1013
1014 let net1_initial_stats = device_net1.get_stats();
1016 let net2_initial_stats = device_net2.get_stats();
1017
1018 crate::early_println!(
1019 "[virtio-net test] Initial stats - net1: TX:{}, RX:{} | net2: TX:{}, RX:{}",
1020 net1_initial_stats.tx_packets,
1021 net1_initial_stats.rx_packets,
1022 net2_initial_stats.tx_packets,
1023 net2_initial_stats.rx_packets
1024 );
1025
1026 let packet_net1_to_net2 = DevicePacket::with_data(vec![0x01, 0x02, 0x03, 0x04, 0xAA]); let packet_net2_to_net1 = DevicePacket::with_data(vec![0x05, 0x06, 0x07, 0x08, 0xBB]); crate::early_println!("[virtio-net test] Sending packet from net1 to net2...");
1032 let result1 = device_net1.transmit_packet(&packet_net1_to_net2);
1033 crate::early_println!(
1034 "[virtio-net test] net1->net2 TX result: {:?}",
1035 result1.is_ok()
1036 );
1037
1038 crate::early_println!("[virtio-net test] Sending packet from net2 to net1...");
1040 let result2 = device_net2.transmit_packet(&packet_net2_to_net1);
1041 crate::early_println!(
1042 "[virtio-net test] net2->net1 TX result: {:?}",
1043 result2.is_ok()
1044 );
1045
1046 crate::early_println!("[virtio-net test] Checking for received packets...");
1048
1049 let received_on_net1 = device_net1.receive_packets();
1050 let received_on_net2 = device_net2.receive_packets();
1051
1052 match received_on_net1 {
1053 Ok(packets) => {
1054 crate::early_println!("[virtio-net test] net1 received {} packets", packets.len());
1055 for (i, packet) in packets.iter().enumerate() {
1056 crate::early_println!(
1057 "[virtio-net test] net1 RX packet {}: {} bytes",
1058 i,
1059 packet.len
1060 );
1061 }
1062 }
1063 Err(e) => crate::early_println!("[virtio-net test] net1 RX error: {}", e),
1064 }
1065
1066 match received_on_net2 {
1067 Ok(packets) => {
1068 crate::early_println!("[virtio-net test] net2 received {} packets", packets.len());
1069 for (i, packet) in packets.iter().enumerate() {
1070 crate::early_println!(
1071 "[virtio-net test] net2 RX packet {}: {} bytes",
1072 i,
1073 packet.len
1074 );
1075 }
1076 }
1077 Err(e) => crate::early_println!("[virtio-net test] net2 RX error: {}", e),
1078 }
1079
1080 let net1_final_stats = device_net1.get_stats();
1082 let net2_final_stats = device_net2.get_stats();
1083
1084 crate::early_println!(
1085 "[virtio-net test] Final stats - net1: TX:{}, RX:{} | net2: TX:{}, RX:{}",
1086 net1_final_stats.tx_packets,
1087 net1_final_stats.rx_packets,
1088 net2_final_stats.tx_packets,
1089 net2_final_stats.rx_packets
1090 );
1091
1092 let net1_tx_delta = net1_final_stats.tx_packets - net1_initial_stats.tx_packets;
1094 let net2_tx_delta = net2_final_stats.tx_packets - net2_initial_stats.tx_packets;
1095
1096 crate::early_println!(
1097 "[virtio-net test] TX deltas - net1: +{}, net2: +{}",
1098 net1_tx_delta,
1099 net2_tx_delta
1100 );
1101 crate::early_println!("[virtio-net test] Bidirectional hub communication test completed");
1102 }
1103
1104 #[test_case]
1105 fn test_virtio_net_device_enumeration() {
1106 crate::early_println!(
1109 "[virtio-net test] Testing device enumeration for multiple virtio-net devices"
1110 );
1111
1112 let devices = [
1113 VirtioNetDevice::new(0x10003000), VirtioNetDevice::new(0x10004000), VirtioNetDevice::new(0x10005000), ];
1117
1118 for (i, device) in devices.iter().enumerate() {
1119 let base_addr = device.get_base_addr();
1120 let mac_result = device.get_mac_address();
1121 let mtu_result = device.get_mtu();
1122 let link_status = device.is_link_up();
1123
1124 crate::early_println!(
1125 "[virtio-net test] Device {}: addr={:#x}, MAC={:?}, MTU={:?}, link={}",
1126 i,
1127 base_addr,
1128 mac_result.is_ok(),
1129 mtu_result.is_ok(),
1130 link_status
1131 );
1132 }
1133
1134 crate::early_println!("[virtio-net test] Device enumeration test completed");
1135 }
1136
1137 #[test_case]
1138 fn test_virtio_net_hub_loopback_with_polling() {
1139 let mut sender_mut = VirtioNetDevice::new(0x10004000);
1141 let mut receiver_mut = VirtioNetDevice::new(0x10005000);
1142
1143 let _ = sender_mut.init_network();
1144 let _ = receiver_mut.init_network();
1145
1146 let test_packet_data = vec![
1148 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x52, 0x54, 0x00, 0x12, 0x34, 0x57, 0x08, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1153 ];
1154 let test_packet = DevicePacket::with_data(test_packet_data);
1155
1156 crate::early_println!("[virtio-net test] Sending test packet from sender device...");
1157 let tx_result = sender_mut.transmit_packet(&test_packet);
1158 crate::early_println!("[virtio-net test] TX result: {:?}", tx_result.is_ok());
1159
1160 crate::early_println!("[virtio-net test] Polling for received packets...");
1162 let mut total_received = 0;
1163
1164 for attempt in 0..5 {
1165 let rx_result = receiver_mut.receive_packets();
1166 match rx_result {
1167 Ok(packets) => {
1168 if !packets.is_empty() {
1169 crate::early_println!(
1170 "[virtio-net test] Attempt {}: Received {} packets",
1171 attempt,
1172 packets.len()
1173 );
1174 total_received += packets.len();
1175
1176 for (i, packet) in packets.iter().enumerate() {
1177 crate::early_println!(
1178 "[virtio-net test] RX packet {}: {} bytes",
1179 i,
1180 packet.len
1181 );
1182 if packet.len >= 8 {
1184 let has_magic = packet.data.len() >= 8
1185 && packet.data[packet.data.len() - 8..packet.data.len()]
1186 == [0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE];
1187 if has_magic {
1188 crate::early_println!(
1189 "[virtio-net test] Found our test packet!"
1190 );
1191 }
1192 }
1193 }
1194 } else {
1195 crate::early_println!(
1196 "[virtio-net test] Attempt {}: No packets received",
1197 attempt
1198 );
1199 }
1200 }
1201 Err(e) => crate::early_println!(
1202 "[virtio-net test] RX error on attempt {}: {}",
1203 attempt,
1204 e
1205 ),
1206 }
1207
1208 for _ in 0..1000 {
1210 core::hint::spin_loop();
1211 }
1212 }
1213
1214 crate::early_println!(
1215 "[virtio-net test] Total received packets: {}",
1216 total_received
1217 );
1218
1219 let sender_stats = sender_mut.get_stats();
1221 let receiver_stats = receiver_mut.get_stats();
1222
1223 crate::early_println!(
1224 "[virtio-net test] Final stats - sender: TX:{}, RX:{} | receiver: TX:{}, RX:{}",
1225 sender_stats.tx_packets,
1226 sender_stats.rx_packets,
1227 receiver_stats.tx_packets,
1228 receiver_stats.rx_packets
1229 );
1230
1231 crate::early_println!("[virtio-net test] Hub loopback with polling test completed");
1232 }
1233
1234 #[test_case]
1235 fn test_virtio_net_qemu_network_configuration() {
1236 crate::early_println!("[virtio-net test] Testing QEMU network configuration understanding");
1238
1239 let device_net0 = VirtioNetDevice::new(0x10003000); let device_net1 = VirtioNetDevice::new(0x10004000); let device_net2 = VirtioNetDevice::new(0x10005000); let devices = [
1253 ("net0", &device_net0, 0x10003000),
1254 ("net1", &device_net1, 0x10004000),
1255 ("net2", &device_net2, 0x10005000),
1256 ];
1257
1258 for (name, device, expected_addr) in &devices {
1259 crate::early_println!("[virtio-net test] Testing device {}", name);
1260
1261 assert_eq!(device.get_base_addr(), *expected_addr);
1262
1263 let mac_result = device.get_mac_address();
1264 let mtu_result = device.get_mtu();
1265 let config_result = device.get_interface_config();
1266 let link_status = device.is_link_up();
1267
1268 crate::early_println!(
1269 "[virtio-net test] {} - base_addr: {:#x}, MAC: {}, MTU: {}, config: {}, link: {}",
1270 name,
1271 device.get_base_addr(),
1272 mac_result.is_ok(),
1273 mtu_result.is_ok(),
1274 config_result.is_ok(),
1275 link_status
1276 );
1277
1278 assert!(mac_result.is_ok(), "{} should have valid MAC", name);
1280 assert!(mtu_result.is_ok(), "{} should have valid MTU", name);
1281 assert!(config_result.is_ok(), "{} should have valid config", name);
1282 }
1284
1285 crate::early_println!("[virtio-net test] QEMU network configuration test completed");
1286 crate::early_println!("[virtio-net test] Net0 (user): TX-only, external connectivity");
1287 crate::early_println!(
1288 "[virtio-net test] Net1, Net2 (hub): Bidirectional, internal loopback"
1289 );
1290 }
1291}