Port virtio-netd to driver-network
This commit is contained in:
Generated
+1
@@ -1796,6 +1796,7 @@ name = "virtio-netd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"driver-network",
|
||||
"futures",
|
||||
"log",
|
||||
"netutils",
|
||||
|
||||
@@ -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"[..],
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user