From 9262d034bd2cd7a2f9be51b6fcc595bd92b7ccbf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:07:17 +0100 Subject: [PATCH] Port virtio-netd to driver-network --- Cargo.lock | 1 + driver-network/src/lib.rs | 5 +++ virtio-netd/Cargo.toml | 1 + virtio-netd/src/main.rs | 92 ++++++++++++++++++++----------------- virtio-netd/src/scheme.rs | 95 ++++++++++----------------------------- 5 files changed, 82 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5accc366e..4e2017a6db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1796,6 +1796,7 @@ name = "virtio-netd" version = "0.1.0" dependencies = [ "common", + "driver-network", "futures", "log", "netutils", diff --git a/driver-network/src/lib.rs b/driver-network/src/lib.rs index 23fcc38135..eec2fc1fcb 100644 --- a/driver-network/src/lib.rs +++ b/driver-network/src/lib.rs @@ -30,6 +30,7 @@ pub trait NetworkAdapter { pub struct NetworkScheme { adapter: T, + _scheme_name: String, scheme: File, next_id: usize, handles: BTreeMap, @@ -44,6 +45,8 @@ enum Handle { impl NetworkScheme { pub fn new(adapter: T, scheme_name: &str) -> Self { + assert_eq!(scheme_name, "network"); // FIXME update fpath before removing this assertion + let scheme_fd = syscall::open( format!(":{scheme_name}"), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -53,6 +56,7 @@ impl NetworkScheme { NetworkScheme { adapter, + _scheme_name: scheme_name.to_owned(), scheme, next_id: 0, handles: BTreeMap::new(), @@ -215,6 +219,7 @@ impl SchemeBlockMut for NetworkScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let scheme_path = match handle { + // FIXME use self.scheme_name instead of hardcoding "network" Handle::Data { .. } => &b"network:"[..], Handle::Mac { .. } => &b"network:mac"[..], }; diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index cf5d40fe74..ae6927fb33 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -11,6 +11,7 @@ futures = { version = "0.3.28", features = ["executor"] } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } common = { path = "../common" } +driver-network = { path = "../driver-network" } redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index c3113ed753..ecda97d2cd 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -2,15 +2,12 @@ mod scheme; use std::fs::File; use std::io::{Read, Write}; -use std::os::fd::{FromRawFd, RawFd}; +use std::mem; +use driver_network::NetworkScheme; use pcid_interface::PcidServerHandle; -use syscall::{Packet, SchemeBlockMut}; - -use virtio_core::transport::{Error, Transport}; - -use scheme::NetworkScheme; +use scheme::VirtioNet; pub const VIRTIO_NET_F_MAC: u32 = 5; @@ -30,7 +27,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::(), 12); const MAX_BUFFER_LEN: usize = 65535; -fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { +fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box> { let mut pcid_handle = PcidServerHandle::connect_default()?; // Double check that we have the right device. @@ -45,20 +42,30 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let device_space = device.device_space; // Negotiate device features: - let mac_addr = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { - let mac = (0..6) - .map(|i| unsafe { core::ptr::read_volatile(device_space.add(i)) }) - .collect::>(); + let mac_address = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { + let mac = unsafe { + [ + core::ptr::read_volatile(device_space.add(0)), + core::ptr::read_volatile(device_space.add(1)), + core::ptr::read_volatile(device_space.add(2)), + core::ptr::read_volatile(device_space.add(3)), + core::ptr::read_volatile(device_space.add(4)), + core::ptr::read_volatile(device_space.add(5)), + ] + }; - let mac_str = format!( - "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + log::info!( + "virtio-net: device MAC is {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] ); - log::info!("virtio-net: device MAC is {mac_str}"); - device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); - mac_str + mac } else { unimplemented!() }; @@ -85,35 +92,38 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let mut name = pci_config.func.name(); name.push_str("_virtio_net"); - // Create the network scheme. - // - // FIXME(andypython): It should be fine to have multiple network devices. - let socket_fd = syscall::open( - &format!(":network"), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, - ) - .map_err(Error::SyscallError)?; + let device = VirtioNet::new(mac_address, rx_queue, tx_queue); + let mut scheme = NetworkScheme::new(device, "network"); - let mut socket_fd = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let mut scheme = NetworkScheme::new(rx_queue, tx_queue); + let _ = netutils::setcfg( + "mac", + &format!( + "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac_address[0], + mac_address[1], + mac_address[2], + mac_address[3], + mac_address[4], + mac_address[5] + ), + ); - let _ = netutils::setcfg("mac", &mac_addr); + let mut event_queue = File::open("event:")?; + event_queue.write(&syscall::Event { + id: scheme.event_handle() as usize, + flags: syscall::EVENT_READ, + data: 0, + })?; - deamon.ready().expect("virtio-netd: failed to deamonize"); + syscall::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); + + daemon.ready().expect("virtio-netd: failed to daemonize"); + + scheme.tick()?; loop { - let mut packet = Packet::default(); - socket_fd - .read(&mut packet) - .expect("virtio-netd: failed to read packet"); - - let result = scheme.handle(&mut packet); - // `packet.a` contains the return value. - packet.a = result.expect("virtio-netd: failed to handle packet"); - - socket_fd - .write(&packet) - .expect("virtio-netd: failed to write packet"); + event_queue.read(&mut [0; mem::size_of::()])?; // Wait for event + scheme.tick()?; } } diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 5a48cba19f..59b3b93e20 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -1,9 +1,6 @@ -use std::collections::BTreeMap; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use syscall::Error as SysError; -use syscall::*; +use driver_network::NetworkAdapter; use common::dma::Dma; @@ -12,26 +9,29 @@ use virtio_core::transport::Queue; use crate::{VirtHeader, MAX_BUFFER_LEN}; -pub struct NetworkScheme<'a> { +pub struct VirtioNet<'a> { + mac_address: [u8; 6], + /// Reciever Queue. rx: Arc>, rx_buffers: Vec>, /// Transmiter Queue. tx: Arc>, - /// File descriptor handles. - handles: BTreeMap, - next_id: AtomicUsize, recv_head: u16, } -impl<'a> NetworkScheme<'a> { - pub fn new(rx: Arc>, tx: Arc>) -> Self { +impl<'a> VirtioNet<'a> { + pub fn new(mac_address: [u8; 6], rx: Arc>, tx: Arc>) -> Self { // Populate all of the `rx_queue` with buffers to maximize performence. let mut rx_buffers = vec![]; for i in 0..(rx.descriptor_len() as usize) { - rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN).unwrap().assume_init() }); + rx_buffers.push(unsafe { + Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN) + .unwrap() + .assume_init() + }); let chain = ChainBuilder::new() .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) @@ -41,13 +41,12 @@ impl<'a> NetworkScheme<'a> { } Self { + mac_address, + rx, rx_buffers, tx, - handles: BTreeMap::new(), - next_id: AtomicUsize::new(0), - recv_head: 0, } } @@ -82,45 +81,27 @@ impl<'a> NetworkScheme<'a> { } } -impl<'a> SchemeBlockMut for NetworkScheme<'a> { - fn open( - &mut self, - _path: &str, - flags: usize, - uid: u32, - _gid: u32, - ) -> syscall::Result> { - if uid != 0 { - return Err(SysError::new(EACCES)); - } - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(id, flags); - - Ok(Some(id)) +impl<'a> NetworkAdapter for VirtioNet<'a> { + fn mac_address(&mut self) -> [u8; 6] { + self.mac_address } - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { - let flags = *self.handles.get(&id).ok_or(SysError::new(EBADF))?; + fn available_for_read(&mut self) -> usize { + (self.rx.used.head_index() - self.recv_head).into() + } + + fn read_packet(&mut self, buf: &mut [u8]) -> syscall::Result> { let bytes = self.try_recv(buf); if bytes != 0 { // We read some bytes. Ok(Some(bytes)) - } else if flags & O_NONBLOCK == O_NONBLOCK { - // We are in non-blocking mode. - Err(SysError::new(EWOULDBLOCK)) } else { - // Block - unimplemented!() + Ok(None) } } - fn write(&mut self, id: usize, buffer: &[u8]) -> syscall::Result> { - if self.handles.get(&id).is_none() { - return Err(SysError::new(EBADF)); - } - + fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result { let header = unsafe { Dma::::zeroed()?.assume_init() }; let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() }; @@ -132,34 +113,6 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { .build(); futures::executor::block_on(self.tx.send(chain)); - Ok(Some(buffer.len())) - } - - fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result> { - unimplemented!() - } - - fn fevent( - &mut self, - id: usize, - _flags: syscall::EventFlags, - ) -> syscall::Result> { - if self.handles.get(&id).is_none() { - return Err(SysError::new(EBADF)); - } - - Ok(Some(syscall::EventFlags::empty())) - } - - fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { - unimplemented!() - } - - fn fsync(&mut self, _id: usize) -> syscall::Result> { - unimplemented!() - } - - fn close(&mut self, _id: usize) -> syscall::Result> { - unimplemented!() + Ok(buffer.len()) } }