Event based ethernetd

This commit is contained in:
Jeremy Soller 2016-10-23 15:26:36 -06:00
parent d208f6aa11
commit eb5ee5edc9
7 changed files with 255 additions and 129 deletions

View file

@ -140,7 +140,8 @@ impl Scheme for Intel8254x {
}
}
Err(Error::new(EWOULDBLOCK))
//Err(Error::new(EWOULDBLOCK))
Ok(0)
}
fn write(&self, _id: usize, buf: &[u8]) -> Result<usize> {
@ -225,6 +226,25 @@ impl Intel8254x {
icr != 0
}
pub fn next_read(&self) -> usize {
let head = unsafe { self.read(RDH) };
let mut tail = unsafe { self.read(RDT) };
tail += 1;
if tail >= self.receive_ring.len() as u32 {
tail = 0;
}
if tail != head {
let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) };
if rd.status & RD_DD == RD_DD {
return rd.length as usize;
}
}
0
}
pub unsafe fn read(&self, register: u32) -> u32 {
ptr::read_volatile((self.base + register as usize) as *mut u32)
}

View file

@ -69,6 +69,11 @@ fn main() {
todo.remove(i);
}
}
let next_read = device_irq.next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
}
Ok(None)
}).expect("e1000d: failed to catch events on IRQ file");

@ -1 +1 @@
Subproject commit a45673aa948fe6d172a0e2b42ade86e0567c3afd
Subproject commit 3eb504dfe131c9fcba3e8ee824f382af9c6032cd

View file

@ -3,6 +3,6 @@ name = "ethernetd"
version = "0.1.0"
[dependencies]
event = { path = "../../crates/event/" }
netutils = { path = "../../programs/netutils/" }
resource_scheme = { path = "../../crates/resource_scheme/" }
syscall = { path = "../../syscall/" }

View file

@ -1,28 +1,88 @@
extern crate event;
extern crate netutils;
extern crate resource_scheme;
extern crate syscall;
use event::EventQueue;
use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Write};
use std::io::{Result, Read, Write};
use std::os::unix::io::FromRawFd;
use std::rc::Rc;
use std::thread;
use resource_scheme::ResourceScheme;
use syscall::Packet;
use syscall::{Packet, SchemeMut, EWOULDBLOCK};
use scheme::EthernetScheme;
mod resource;
mod scheme;
fn main() {
thread::spawn(move || {
let mut socket = File::create(":ethernet").expect("ethernetd: failed to create ethernet scheme");
let scheme = EthernetScheme;
loop {
let network_fd = syscall::open("network:", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ethernetd: failed to open network");
let network = unsafe { File::from_raw_fd(network_fd) };
let socket_fd = syscall::open(":ethernet", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ethernetd: failed to create ethernet scheme");
let socket = Rc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) }));
let scheme = Rc::new(RefCell::new(EthernetScheme::new(network)));
let todo = Rc::new(RefCell::new(Vec::<Packet>::new()));
let mut event_queue = EventQueue::<()>::new().expect("ethernetd: failed to create event queue");
let socket_net = socket.clone();
let scheme_net = scheme.clone();
let todo_net = todo.clone();
event_queue.add(network_fd, move |_count: usize| -> Result<Option<()>> {
if scheme_net.borrow_mut().input()? > 0 {
let mut todo = todo_net.borrow_mut();
let mut i = 0;
while i < todo.len() {
let a = todo[i].a;
scheme_net.borrow_mut().handle(&mut todo[i]);
if todo[i].a == (-EWOULDBLOCK) as usize {
todo[i].a = a;
i += 1;
} else {
socket_net.borrow_mut().write(&mut todo[i])?;
todo.remove(i);
}
}
for (id, handle) in scheme_net.borrow_mut().handles.iter() {
if let Some(frame) = handle.frames.get(0) {
socket_net.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *id,
c: syscall::flag::EVENT_READ,
d: frame.data.len()
})?;
}
}
}
Ok(None)
}).expect("ethernetd: failed to listen for network events");
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<()>> {
let mut packet = Packet::default();
socket.read(&mut packet).expect("ethernetd: failed to read events from ethernet scheme");
scheme.handle(&mut packet);
socket.write(&packet).expect("ethernetd: failed to write responses to ethernet scheme");
}
socket.borrow_mut().read(&mut packet)?;
let a = packet.a;
scheme.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket.borrow_mut().write(&mut packet)?;
}
Ok(None)
}).expect("ethernetd: failed to listen for scheme events");
event_queue.run().expect("ethernetd: failed to run event loop");
});
}

View file

@ -1,96 +0,0 @@
use std::{cmp, mem};
use netutils::{n16, MacAddr, EthernetIIHeader, EthernetII};
use resource_scheme::Resource;
use syscall;
use syscall::error::*;
/// A ethernet resource
pub struct EthernetResource {
/// The network
pub network: usize,
/// The data
pub data: Vec<u8>,
/// The MAC addresss
pub peer_addr: MacAddr,
/// The ethernet type
pub ethertype: u16,
}
impl Resource for EthernetResource {
fn dup(&self) -> Result<Box<Self>> {
let network = try!(syscall::dup(self.network));
Ok(Box::new(EthernetResource {
network: network,
data: self.data.clone(),
peer_addr: self.peer_addr,
ethertype: self.ethertype,
}))
}
fn path(&self, buf: &mut [u8]) -> Result<usize> {
let path_string = format!("ethernet:{}/{:X}", self.peer_addr.to_string(), self.ethertype);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.data.is_empty() {
let mut data: Vec<u8> = Vec::new();
mem::swap(&mut self.data, &mut data);
for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d;
}
return Ok(cmp::min(buf.len(), data.len()));
}
let mut bytes = [0; 65536];
let count = try!(syscall::read(self.network, &mut bytes));
if let Some(frame) = EthernetII::from_bytes(&bytes[..count]) {
if frame.header.ethertype.get() == self.ethertype {
for (b, d) in buf.iter_mut().zip(frame.data.iter()) {
*b = *d;
}
return Ok(cmp::min(buf.len(), frame.data.len()));
}
}
Ok(0)
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let data = Vec::from(buf);
match syscall::write(self.network, &EthernetII {
header: EthernetIIHeader {
src: MacAddr { bytes: [0x50, 0x51, 0x52, 0x53, 0x54, 0x55] },
dst: self.peer_addr,
ethertype: n16::new(self.ethertype),
},
data: data,
}
.to_bytes()) {
Ok(_) => Ok(buf.len()),
Err(err) => Err(err),
}
}
fn sync(&mut self) -> Result<usize> {
syscall::fsync(self.network)
}
}
impl Drop for EthernetResource {
fn drop(&mut self) {
let _ = syscall::close(self.network);
}
}

View file

@ -1,18 +1,64 @@
use std::{str, u16};
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{self, Read};
use std::os::unix::io::AsRawFd;
use std::{cmp, str, u16};
use netutils::{MacAddr, EthernetII};
use resource_scheme::ResourceScheme;
use netutils::{getcfg, n16, MacAddr, EthernetII, EthernetIIHeader};
use syscall;
use syscall::error::{Error, Result, EACCES, ENOENT, EINVAL};
use syscall::error::{Error, Result, EACCES, EBADF, ENOENT, EINVAL, EWOULDBLOCK};
use syscall::flag::O_RDWR;
use syscall::scheme::SchemeMut;
use resource::EthernetResource;
#[derive(Clone)]
pub struct Handle {
/// The Host's MAC address
pub host_addr: MacAddr,
/// The Peer's MAC address
pub peer_addr: MacAddr,
/// The ethernet type
pub ethertype: u16,
/// The data
pub frames: VecDeque<EthernetII>,
}
pub struct EthernetScheme;
pub struct EthernetScheme {
network: File,
next_id: usize,
pub handles: BTreeMap<usize, Handle>
}
impl ResourceScheme<EthernetResource> for EthernetScheme {
fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Box<EthernetResource>> {
impl EthernetScheme {
pub fn new(network: File) -> EthernetScheme {
EthernetScheme {
network: network,
next_id: 1,
handles: BTreeMap::new(),
}
}
//TODO: Minimize allocation
//TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?)
pub fn input(&mut self) -> io::Result<usize> {
let mut bytes = [0; 65536];
let count = self.network.read(&mut bytes)?;
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
for (_id, handle) in self.handles.iter_mut() {
if frame.header.ethertype.get() == handle.ethertype {
handle.frames.push_back(frame.clone());
}
}
Ok(count)
} else {
Ok(0)
}
}
}
impl SchemeMut for EthernetScheme {
fn open(&mut self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split("/");
if let Some(host_string) = parts.next() {
@ -20,13 +66,18 @@ impl ResourceScheme<EthernetResource> for EthernetScheme {
if let Ok(network) = syscall::open("network:", O_RDWR) {
let ethertype = u16::from_str_radix(ethertype_string, 16).unwrap_or(0) as u16;
if !host_string.is_empty() {
return Ok(Box::new(EthernetResource {
network: network,
data: Vec::new(),
if ! host_string.is_empty() {
let next_id = self.next_id;
self.next_id += 1;
self.handles.insert(next_id, Handle {
host_addr: mac_addr,
peer_addr: MacAddr::from_str(host_string),
ethertype: ethertype,
}));
frames: VecDeque::new()
});
return Ok(next_id);
} else {
loop {
let mut bytes = [0; 65536];
@ -34,12 +85,22 @@ impl ResourceScheme<EthernetResource> for EthernetScheme {
Ok(count) => {
if let Some(frame) = EthernetII::from_bytes(&bytes[..count]) {
if frame.header.ethertype.get() == ethertype {
return Ok(Box::new(EthernetResource {
network: network,
data: frame.data,
peer_addr: frame.header.src,
let next_id = self.next_id;
self.next_id += 1;
let peer_addr = frame.header.src;
let mut frames = VecDeque::new();
frames.push_back(frame);
self.handles.insert(next_id, Handle {
host_addr: mac_addr,
peer_addr: peer_addr,
ethertype: ethertype,
}));
frames: frames
});
return Ok(next_id);
}
}
}
@ -62,4 +123,80 @@ impl ResourceScheme<EthernetResource> for EthernetScheme {
Err(Error::new(EACCES))
}
}
fn dup(&mut self, id: usize) -> Result<usize> {
let next_id = self.next_id;
self.next_id += 1;
let handle = {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
handle.clone()
};
self.handles.insert(next_id, handle);
Ok(next_id)
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if let Some(frame) = handle.frames.pop_front() {
for (b, d) in buf.iter_mut().zip(frame.data.iter()) {
*b = *d;
}
Ok(cmp::min(buf.len(), frame.data.len()))
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
match syscall::write(self.network.as_raw_fd(), &EthernetII {
header: EthernetIIHeader {
src: handle.host_addr,
dst: handle.peer_addr,
ethertype: n16::new(handle.ethertype),
},
data: Vec::from(buf),
}
.to_bytes()) {
Ok(_) => Ok(buf.len()),
Err(err) => Err(err),
}
}
fn fevent(&mut self, id: usize, _flags: usize) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
Ok(id)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("ethernet:{}/{:X}", handle.peer_addr.to_string(), handle.ethertype);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
fn fsync(&mut self, id: usize) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
syscall::fsync(self.network.as_raw_fd())
}
fn close(&mut self, id: usize) -> Result<usize> {
let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
drop(handle);
Ok(0)
}
}