kernel/drivers/network/
virtio_net.rs

1//! # VirtIO Network Device Driver
2//!
3//! This module provides a driver for VirtIO network devices, implementing the
4//! NetworkDevice trait for integration with the kernel's network subsystem.
5//!
6//! The driver supports basic network operations (packet transmission and reception)
7//! and handles the VirtIO queue management for network device requests.
8//!
9//! ## VirtIO Network Device Features
10//!
11//! The driver checks for and handles the following VirtIO network device features:
12//! - Basic packet transmission and reception
13//! - MAC address configuration
14//! - MTU management
15//! - Link status detection
16//!
17//! ## Implementation Details
18//!
19//! The driver uses two virtqueues:
20//! - Receive queue (index 0): For receiving packets from the network
21//! - Transmit queue (index 1): For sending packets to the network
22//!
23//! Each network packet is handled through the VirtIO descriptor chain mechanism,
24//! with proper memory management for packet buffers.
25
26use 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
51// VirtIO Network Feature bits
52const VIRTIO_NET_F_CSUM: u32 = 0; // Device handles packets with partial checksum
53const VIRTIO_NET_F_GUEST_CSUM: u32 = 1; // Guest handles packets with partial checksum
54const VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: u32 = 2; // Control channel offloads reconfiguration support
55const VIRTIO_NET_F_MTU: u32 = 3; // Device maximum MTU reporting supported
56const VIRTIO_NET_F_MAC: u32 = 5; // Device has given MAC address
57const VIRTIO_NET_F_GUEST_TSO4: u32 = 7; // Guest can handle TSOv4
58const VIRTIO_NET_F_GUEST_TSO6: u32 = 8; // Guest can handle TSOv6
59const VIRTIO_NET_F_GUEST_ECN: u32 = 9; // Guest can handle TSO with ECN
60const VIRTIO_NET_F_GUEST_UFO: u32 = 10; // Guest can handle UFO
61const VIRTIO_NET_F_HOST_TSO4: u32 = 11; // Device can handle TSOv4
62const VIRTIO_NET_F_HOST_TSO6: u32 = 12; // Device can handle TSOv6
63const VIRTIO_NET_F_HOST_ECN: u32 = 13; // Device can handle TSO with ECN
64const VIRTIO_NET_F_HOST_UFO: u32 = 14; // Device can handle UFO
65const VIRTIO_NET_F_MRG_RXBUF: u32 = 15; // Guest can merge receive buffers
66const VIRTIO_NET_F_STATUS: u32 = 16; // Configuration status field available
67const VIRTIO_NET_F_CTRL_VQ: u32 = 17; // Control channel available
68const VIRTIO_NET_F_CTRL_RX: u32 = 18; // Control channel RX mode support
69const VIRTIO_NET_F_CTRL_VLAN: u32 = 19; // Control channel VLAN filtering
70const VIRTIO_NET_F_GUEST_ANNOUNCE: u32 = 21; // Guest can send gratuitous packets
71const VIRTIO_NET_F_MQ: u32 = 22; // Device supports multiqueue with automatic receive steering
72const VIRTIO_NET_F_CTRL_MAC_ADDR: u32 = 23; // Set MAC address through control channel
73
74// VirtIO Network Status bits
75const VIRTIO_NET_S_LINK_UP: u16 = 1; // Link is up
76const VIRTIO_NET_S_ANNOUNCE: u16 = 2; // Gratuitous packets should be sent
77
78// Default MTU if not specified
79const DEFAULT_MTU: usize = 1500;
80
81/// VirtIO Network Device Configuration
82#[repr(C)]
83pub struct VirtioNetConfig {
84    pub mac: [u8; 6],             // MAC address
85    pub status: u16,              // Status
86    pub max_virtqueue_pairs: u16, // Maximum number of virtqueue pairs
87    pub mtu: u16,                 // MTU
88}
89
90/// VirtIO Network Header (for packet transmission/reception)
91#[repr(C)]
92#[derive(Debug, Clone, Copy)]
93pub struct VirtioNetHdr {
94    pub flags: u8,        // Flags
95    pub gso_type: u8,     // GSO type
96    pub hdr_len: u16,     // Header length
97    pub gso_size: u16,    // GSO size
98    pub csum_start: u16,  // Checksum start
99    pub csum_offset: u16, // Checksum offset
100    pub num_buffers: u16, // Number of buffers (for mergeable rx buffers)
101}
102
103/// Basic VirtIO Network Header (without num_buffers field)
104#[repr(C)]
105#[derive(Debug, Clone, Copy)]
106pub struct VirtioNetHdrBasic {
107    pub flags: u8,        // Flags
108    pub gso_type: u8,     // GSO type
109    pub hdr_len: u16,     // Header length
110    pub gso_size: u16,    // GSO size
111    pub csum_start: u16,  // Checksum start
112    pub csum_offset: u16, // Checksum offset
113}
114
115impl VirtioNetHdr {
116    /// Create a new default network header
117    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    /// Create a new default basic network header
132    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
144/// VirtIO Network Device
145pub struct VirtioNetDevice {
146    base_addr: usize,
147    virtqueues: Mutex<[VirtQueue<'static>; 2]>, // RX queue (0) and TX queue (1)
148    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    /// Create a new VirtIO Network device
159    ///
160    /// # Arguments
161    ///
162    /// * `base_addr` - The base address of the device
163    ///
164    /// # Returns
165    ///
166    /// A new instance of `VirtioNetDevice`
167    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)]), // RX and TX queues
171            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        // Initialize the VirtIO device first
181        let negotiated_features = match device.init() {
182            Ok(features) => features,
183            Err(e) => panic!("Failed to initialize VirtIO Network Device: {}", e),
184        };
185
186        // Read device configuration with the negotiated features
187        device.read_device_config(negotiated_features);
188
189        // Prefill RX virtqueue buffers early.
190        // Without RX descriptors posted, QEMU may log
191        // `virtio: bogus descriptor or out of resources` when it tries to
192        // deliver packets to a ready virtio-net device.
193        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                // Register with EthernetLayer for multi-interface support
212                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    /// Read device configuration from the VirtIO config space
250    fn read_device_config(&mut self, negotiated_features: u32) {
251        // Store actually negotiated features
252        *self.features.write() = negotiated_features;
253
254        // Debug: Print negotiated features in test builds
255        #[cfg(test)]
256        {
257            use crate::{drivers::virtio::device::Register, early_println};
258            // Also read device features for debugging
259            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        // Read MAC address if supported
271        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            // Generate a default MAC address
278            mac_addr = [0x52, 0x54, 0x00, 0x12, 0x34, 0x56];
279        }
280
281        // Read MTU if supported
282        let mtu = if negotiated_features & (1 << VIRTIO_NET_F_MTU) != 0 {
283            self.read_config::<u16>(12) as usize // MTU at offset 12
284        } else {
285            DEFAULT_MTU
286        };
287
288        // Create network interface configuration
289        let mac = MacAddress::new(mac_addr);
290        let config = NetworkInterfaceConfig::new(mac, mtu, "virtio-net");
291        *self.config.write() = Some(config);
292    }
293
294    /// Get the appropriate header size based on device features
295    fn get_header_size(&self) -> usize {
296        // Always use basic header since we don't support mergeable RX buffers
297        mem::size_of::<VirtioNetHdrBasic>()
298    }
299
300    /// Setup receive buffers in the RX queue
301    fn setup_rx_buffers(&self) -> Result<(), &'static str> {
302        let mut virtqueues = self.virtqueues.lock();
303        let rx_queue = &mut virtqueues[0]; // RX queue is index 0
304
305        // Use standard single-buffer approach like Linux virtio-net
306        let buffer_count = 16; // Provide extra RX headroom
307
308        for _ in 0..buffer_count {
309            let hdr_size = self.get_header_size(); // 10 bytes for VirtioNetHdrBasic
310            let packet_size = 1514; // Standard Ethernet frame size
311            let total_size = hdr_size + packet_size;
312
313            // Allocate single contiguous buffer - this is the standard approach
314            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            // Allocate single descriptor for the entire receive buffer
319            let desc_idx = rx_queue
320                .alloc_desc()
321                .ok_or("Failed to allocate RX descriptor")?;
322
323            // Setup descriptor - device writes virtio-net header + packet data here
324            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; // Device writes
330            rx_queue.desc[desc_idx].next = 0; // No chaining
331
332            // Add to available ring
333            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            // Store buffer pointer for cleanup
342            self.rx_buffers
343                .lock()
344                .push(unsafe { Box::from_raw(buffer_ptr) });
345        }
346
347        // Notify device about available RX buffers
348        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); // Notify RX queue
353
354        Ok(())
355    }
356
357    /// Process a single packet transmission
358    fn transmit_packet(&self, packet: &DevicePacket) -> Result<(), &'static str> {
359        // combine header and packet in single buffer like their send() function
360        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        // Create single buffer with header first, followed by packet data
366        let mut combined_buffer = vec![0u8; total_size];
367
368        // Fill header at the beginning
369        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        // Copy packet data after header
379        combined_buffer[hdr_size..].copy_from_slice(&packet.data[..packet.len]);
380
381        // Convert to stable memory allocation
382        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]; // TX queue is index 1
388
389            // Single descriptor for the combined buffer
390            let desc_idx = tx_queue
391                .alloc_desc()
392                .ok_or("Failed to allocate TX descriptor")?;
393
394            // Setup descriptor for the combined buffer (device readable)
395            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; // No flags, single descriptor
401            tx_queue.desc[desc_idx].next = 0; // No chaining
402
403            // Submit the request to the queue
404            if let Err(e) = tx_queue.push(desc_idx) {
405                tx_queue.free_desc(desc_idx);
406                return Err(e);
407            }
408
409            // Notify the device
410            self.notify(1); // Notify TX queue
411
412            // Wait for transmission (polling)
413            while tx_queue.is_busy() {}
414
415            // Get completion
416            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            // Free descriptor after processing (responsibility of driver)
425            tx_queue.free_desc(desc_idx);
426
427            result
428        };
429
430        // Cleanup memory
431        unsafe {
432            drop(Box::from_raw(buffer_ptr));
433        }
434
435        // Update statistics if transmission succeeded
436        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    /// Process received packets from RX queue
446    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]; // RX queue is index 0
450
451        let mut buffers_recycled = 0usize;
452
453        // Process all completed RX descriptors
454        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        // Always notify device if we recycled any buffers, so it knows RX buffers are available
487        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); // Notify RX queue
493        }
494
495        // Update statistics if we received packets
496        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    /// Check link status from device configuration
506    fn check_link_status(&self) -> bool {
507        let features = *self.features.read();
508        if features & (1 << VIRTIO_NET_F_STATUS) != 0 {
509            // Read status from config space
510            let status = self.read_config::<u16>(6); // Status at offset 6
511            (status & VIRTIO_NET_S_LINK_UP) != 0
512        } else {
513            // Assume link is up if status feature is not supported
514            true
515        }
516    }
517
518    /// Enable interrupts for this device
519    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    /// Set interface name for interrupt dispatch
536    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        // VirtIO network devices don't support memory mapping
552    }
553
554    fn on_unmapped(&self, _vaddr: usize, _length: usize) {
555        // VirtIO network devices don't support memory mapping
556    }
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    // VirtIO network devices don't support control operations by default
587    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 // TX and RX queues
650    }
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        // Debug: Print detailed feature analysis
666        #[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        // Use virtio-blk style: accept most features, exclude problematic ones
694        // Start with all device features and exclude specific ones we don't want
695        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            // TODO: Implement EVENT_IDX before negotiating it.
703            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        // TODO: Implement via control queue if VIRTIO_NET_F_CTRL_RX is supported
797        // For now, just return success
798        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        // Setup RX buffers with separated descriptors for header and data
811        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        // Device should have default configuration after creation
863        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        // Test network initialization
877        assert!(device.init_network().is_ok());
878
879        // Should not fail on subsequent initialization
880        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        // Link status depends on device configuration
888        // In test environment, this may vary
889        let _link_up = device.is_link_up();
890        // We can't assert specific value since it depends on test setup
891    }
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        // Send some test packets if link is up
905        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); // Sum of packet sizes
915        }
916    }
917
918    #[test_case]
919    fn test_virtio_net_promiscuous_mode() {
920        let device = VirtioNetDevice::new(0x10003000);
921
922        // Should succeed (no-op in current implementation)
923        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        // Create a test packet
932        let test_data = vec![0x45, 0x00, 0x00, 0x3c]; // Simple IP header start
933        let packet = DevicePacket::with_data(test_data);
934
935        // Test packet transmission - should not panic
936        let result = device.transmit_packet(&packet);
937        // In test environment, TX may complete or timeout - both are acceptable
938        // What matters is that we don't crash or leave device in broken state
939        match result {
940            Ok(_) => {
941                // TX completed successfully
942                crate::early_println!("[virtio-net test] TX completed successfully");
943            }
944            Err(e) => {
945                // TX timed out or failed - acceptable in test environment
946                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        // Test multiple packet transmission
956        for i in 0..3 {
957            let mut test_data = vec![0x45, 0x00, 0x00, 0x3c];
958            test_data.push(i as u8); // Make each packet unique
959            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        // Test creating multiple devices (simulating net0, net1, net2)
973        let device1 = VirtioNetDevice::new(0x10003000); // net0 - user netdev
974        let device2 = VirtioNetDevice::new(0x10004000); // net1 - hub netdev
975        let device3 = VirtioNetDevice::new(0x10005000); // net2 - hub netdev
976
977        // Verify each device has unique base addresses
978        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        // All devices should have proper configuration
983        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        // Test sending packet on each device
990        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        // Test hub-connected devices for bidirectional communication
1003        // This simulates the actual QEMU setup with hub networking
1004        let device_net1 = VirtioNetDevice::new(0x10004000); // net1 - hub device 1
1005        let device_net2 = VirtioNetDevice::new(0x10005000); // net2 - hub device 2
1006
1007        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        // Get initial stats for both devices
1015        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        // Prepare test packets with unique identifiers
1027        let packet_net1_to_net2 = DevicePacket::with_data(vec![0x01, 0x02, 0x03, 0x04, 0xAA]); // net1->net2
1028        let packet_net2_to_net1 = DevicePacket::with_data(vec![0x05, 0x06, 0x07, 0x08, 0xBB]); // net2->net1
1029
1030        // Test 1: Send packet from net1 to net2
1031        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        // Test 2: Send packet from net2 to net1
1039        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        // Test 3: Check for received packets on both devices
1047        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        // Check final statistics
1081        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        // Verify that at least transmission statistics were updated
1093        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        // Test that we can properly enumerate and differentiate multiple devices
1107        // This helps verify that the device manager properly detects all virtio-net devices
1108        crate::early_println!(
1109            "[virtio-net test] Testing device enumeration for multiple virtio-net devices"
1110        );
1111
1112        let devices = [
1113            VirtioNetDevice::new(0x10003000), // bus.2 - net0 (user)
1114            VirtioNetDevice::new(0x10004000), // bus.3 - net1 (hub)
1115            VirtioNetDevice::new(0x10005000), // bus.4 - net2 (hub)
1116        ];
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        // Initialize both devices for network operations
1140        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        // Create a distinctive test packet
1147        let test_packet_data = vec![
1148            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Dest MAC (broadcast)
1149            0x52, 0x54, 0x00, 0x12, 0x34, 0x57, // Src MAC (matching net1 default)
1150            0x08, 0x00, // Ethernet type (IPv4)
1151            // Simple payload for identification
1152            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        // Poll for received packets with multiple attempts
1161        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                            // Check if this might be our test packet
1183                            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            // Small delay between polling attempts (in a real system, this would be interrupt-driven)
1209            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        // Verify device statistics
1220        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        // Test that verifies our understanding of QEMU network setup
1237        crate::early_println!("[virtio-net test] Testing QEMU network configuration understanding");
1238
1239        // Expected device configuration based on test.sh setup:
1240        // -device virtio-net-device,netdev=net0,mac=52:54:00:12:34:56,bus=virtio-mmio-bus.2
1241        // -device virtio-net-device,netdev=net1,mac=52:54:00:12:34:57,bus=virtio-mmio-bus.3
1242        // -device virtio-net-device,netdev=net2,mac=52:54:00:12:34:58,bus=virtio-mmio-bus.4
1243        // -netdev user,id=net0
1244        // -netdev hubport,id=net1,hubid=0
1245        // -netdev hubport,id=net2,hubid=0
1246
1247        let device_net0 = VirtioNetDevice::new(0x10003000); // bus.2 -> user netdev
1248        let device_net1 = VirtioNetDevice::new(0x10004000); // bus.3 -> hub netdev
1249        let device_net2 = VirtioNetDevice::new(0x10005000); // bus.4 -> hub netdev
1250
1251        // Verify all devices are properly configured
1252        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            // All devices should be properly configured
1279            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            // Note: link status may vary depending on QEMU setup, so we don't assert it
1283        }
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}