Port virtio-netd to driver-network

This commit is contained in:
bjorn3
2024-02-27 14:07:17 +01:00
parent de6beb8992
commit 9262d034bd
5 changed files with 82 additions and 112 deletions
Generated
+1
View File
@@ -1796,6 +1796,7 @@ name = "virtio-netd"
version = "0.1.0"
dependencies = [
"common",
"driver-network",
"futures",
"log",
"netutils",
+5
View File
@@ -30,6 +30,7 @@ pub trait NetworkAdapter {
pub struct NetworkScheme<T: NetworkAdapter> {
adapter: T,
_scheme_name: String,
scheme: File,
next_id: usize,
handles: BTreeMap<usize, Handle>,
@@ -44,6 +45,8 @@ enum Handle {
impl<T: NetworkAdapter> NetworkScheme<T> {
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<T: NetworkAdapter> NetworkScheme<T> {
NetworkScheme {
adapter,
_scheme_name: scheme_name.to_owned(),
scheme,
next_id: 0,
handles: BTreeMap::new(),
@@ -215,6 +219,7 @@ impl<T: NetworkAdapter> SchemeBlockMut for NetworkScheme<T> {
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"[..],
};
+1
View File
@@ -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"
+51 -41
View File
@@ -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::<VirtHeader>(), 12);
const MAX_BUFFER_LEN: usize = 65535;
fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> {
fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box<dyn std::error::Error>> {
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::<Vec<u8>>();
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::<syscall::Event>()])?; // Wait for event
scheme.tick()?;
}
}
+24 -71
View File
@@ -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<Queue<'a>>,
rx_buffers: Vec<Dma<[u8]>>,
/// Transmiter Queue.
tx: Arc<Queue<'a>>,
/// File descriptor handles.
handles: BTreeMap<usize, usize>,
next_id: AtomicUsize,
recv_head: u16,
}
impl<'a> NetworkScheme<'a> {
pub fn new(rx: Arc<Queue<'a>>, tx: Arc<Queue<'a>>) -> Self {
impl<'a> VirtioNet<'a> {
pub fn new(mac_address: [u8; 6], rx: Arc<Queue<'a>>, tx: Arc<Queue<'a>>) -> 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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
if self.handles.get(&id).is_none() {
return Err(SysError::new(EBADF));
}
fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result<usize> {
let header = unsafe { Dma::<VirtHeader>::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<Option<usize>> {
unimplemented!()
}
fn fevent(
&mut self,
id: usize,
_flags: syscall::EventFlags,
) -> syscall::Result<Option<syscall::EventFlags>> {
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<Option<usize>> {
unimplemented!()
}
fn fsync(&mut self, _id: usize) -> syscall::Result<Option<usize>> {
unimplemented!()
}
fn close(&mut self, _id: usize) -> syscall::Result<Option<usize>> {
unimplemented!()
Ok(buffer.len())
}
}