parent
50d12e7113
commit
449b8a0a67
@ -0,0 +1,274 @@
|
|||||||
|
#![feature(alloc)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate rcore_user;
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use rcore_user::syscall::*;
|
||||||
|
use isomorphic_drivers::net::ethernet::intel::ixgbe;
|
||||||
|
use isomorphic_drivers::provider;
|
||||||
|
use alloc::prelude::*;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::vec;
|
||||||
|
|
||||||
|
use smoltcp::iface::*;
|
||||||
|
use smoltcp::phy;
|
||||||
|
use smoltcp::phy::*;
|
||||||
|
use smoltcp::socket::*;
|
||||||
|
use smoltcp::time::*;
|
||||||
|
use smoltcp::wire::*;
|
||||||
|
use smoltcp::Result;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Provider;
|
||||||
|
|
||||||
|
impl Provider {
|
||||||
|
pub fn new() -> Box<Provider> {
|
||||||
|
Box::new(Provider {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl provider::Provider for Provider {
|
||||||
|
/// Get page size
|
||||||
|
fn get_page_size(&self) -> usize {
|
||||||
|
4096
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate virtual address to physical address
|
||||||
|
fn translate_va(&self, va: usize) -> usize {
|
||||||
|
let mut pa = [0u64; 1];
|
||||||
|
sys_get_paddr(&[va as u64], &mut pa[..]);
|
||||||
|
pa[0] as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bulk translate virtual addresses to physical addresses for performance
|
||||||
|
fn translate_vas(&self, vas: &[usize]) -> Vec<usize> {
|
||||||
|
let mut pas = vec![0u64; vas.len()];
|
||||||
|
let mut vec_vas = vec![0u64; vas.len()];
|
||||||
|
for va in vas.iter() {
|
||||||
|
vec_vas.push(*va as u64);
|
||||||
|
}
|
||||||
|
sys_get_paddr(&vec_vas[..], &mut pas[..]);
|
||||||
|
let mut res = vec![0usize; vas.len()];
|
||||||
|
for pa in pas {
|
||||||
|
res.push(pa as usize);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct IXGBEDriver {
|
||||||
|
inner: ixgbe::IXGBEDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IXGBERxToken(Vec<u8>);
|
||||||
|
pub struct IXGBETxToken(IXGBEDriver);
|
||||||
|
|
||||||
|
impl<'a> phy::Device<'a> for IXGBEDriver {
|
||||||
|
type RxToken = IXGBERxToken;
|
||||||
|
type TxToken = IXGBETxToken;
|
||||||
|
|
||||||
|
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||||
|
if self.inner.can_send() {
|
||||||
|
if let Some(data) = self.inner.recv() {
|
||||||
|
Some((IXGBERxToken(data), IXGBETxToken(self.clone())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||||
|
if self.inner.can_send() {
|
||||||
|
Some(IXGBETxToken(self.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capabilities(&self) -> DeviceCapabilities {
|
||||||
|
let mut caps = DeviceCapabilities::default();
|
||||||
|
caps.max_transmission_unit = ixgbe::IXGBEDriver::get_mtu(); // max MTU
|
||||||
|
//caps.max_transmission_unit = 1500; // max MTU
|
||||||
|
caps.max_burst_size = Some(256);
|
||||||
|
// IP Rx checksum is offloaded with RXCSUM
|
||||||
|
caps.checksum.ipv4 = Checksum::Tx;
|
||||||
|
caps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl phy::RxToken for IXGBERxToken {
|
||||||
|
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&[u8]) -> Result<R>,
|
||||||
|
{
|
||||||
|
f(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl phy::TxToken for IXGBETxToken {
|
||||||
|
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||||
|
{
|
||||||
|
let mut buffer = [0u8; ixgbe::IXGBEDriver::get_mtu()];
|
||||||
|
let result = f(&mut buffer[..len]);
|
||||||
|
if result.is_ok() {
|
||||||
|
(self.0).inner.send(&buffer[..len]);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
enum State {
|
||||||
|
BEGIN,
|
||||||
|
CONTROL_SOCKET_CONNECT,
|
||||||
|
CONTROL_COOKIE_SENT,
|
||||||
|
JSON_CONFIG_SENT,
|
||||||
|
CREATE_STREAMS,
|
||||||
|
DATA_SOCKET_CONNECT,
|
||||||
|
DATA_COOKIE_SENT,
|
||||||
|
TEST_START,
|
||||||
|
TEST_RUNNING
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPORTANT: Must define main() like this
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn main() {
|
||||||
|
println!("I am going to map IXGBE driver to user space");
|
||||||
|
println!("Kernel network stack should not use it anymore");
|
||||||
|
let addr = sys_map_pci_device(0x8086, 0x10fb);
|
||||||
|
println!("IXGBE addr at {:#X}", addr);
|
||||||
|
let ixgbe = ixgbe::IXGBEDriver::init(Provider::new(), addr as usize, 0x20000);
|
||||||
|
println!("IXGBE driver up");
|
||||||
|
println!("IXGBE driver waiting for link up");
|
||||||
|
while !ixgbe.is_link_up() {}
|
||||||
|
println!("IXGBE driver link is up");
|
||||||
|
|
||||||
|
let ethernet_addr = ixgbe.get_mac();
|
||||||
|
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 2), 24)];
|
||||||
|
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||||
|
let mut iface = EthernetInterfaceBuilder::new(IXGBEDriver{ inner:ixgbe })
|
||||||
|
.ethernet_addr(EthernetAddress::from_bytes(ðernet_addr.as_bytes()))
|
||||||
|
.ip_addrs(ip_addrs)
|
||||||
|
.neighbor_cache(neighbor_cache)
|
||||||
|
.finalize();
|
||||||
|
|
||||||
|
// 37 byte ascii cookie
|
||||||
|
let cookie = String::from("cafebabed00dbeefELFGIF89aPKGET/HTTP/\0").into_bytes();
|
||||||
|
assert_eq!(cookie.len(), 37);
|
||||||
|
// Json config
|
||||||
|
let json = String::from(r##"{"tcp":true,"omit":0,"time":10,"parallel":1,"len":2147483647,"pacing_timer":1000,"client_version":"3.6"}"##).into_bytes();
|
||||||
|
println!("Waiting for 3s");
|
||||||
|
sys_sleep(3);
|
||||||
|
println!("Simulating iperf3 client to 10.0.0.1");
|
||||||
|
|
||||||
|
// tcp for control, tcp2 for data
|
||||||
|
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 204800]);
|
||||||
|
let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 204800]);
|
||||||
|
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||||
|
|
||||||
|
let tcp2_rx_buffer = TcpSocketBuffer::new(vec![0; 204800]);
|
||||||
|
let tcp2_tx_buffer = TcpSocketBuffer::new(vec![0; 204800]);
|
||||||
|
let tcp2_socket = TcpSocket::new(tcp2_rx_buffer, tcp2_tx_buffer);
|
||||||
|
|
||||||
|
let mut sockets = SocketSet::new(vec![]);
|
||||||
|
let tcp_handle = sockets.add(tcp_socket);
|
||||||
|
let tcp2_handle = sockets.add(tcp2_socket);
|
||||||
|
|
||||||
|
let mut tick = 0;
|
||||||
|
let mut state = State::BEGIN;
|
||||||
|
let mut last_state = State::BEGIN;
|
||||||
|
let data = [0u8; 204800];
|
||||||
|
loop {
|
||||||
|
tick += 1;
|
||||||
|
iface.poll(&mut sockets, Instant::from_millis(tick / 1000));
|
||||||
|
{
|
||||||
|
let mut socket = sockets.get::<TcpSocket>(tcp_handle);
|
||||||
|
if let State::BEGIN = state {
|
||||||
|
socket.connect(IpEndpoint::new(IpAddress::v4(10, 0, 0, 1), 5201),
|
||||||
|
IpEndpoint::new(IpAddress::v4(10, 0, 0, 2), 5201)).unwrap();
|
||||||
|
state = State::CONTROL_SOCKET_CONNECT;
|
||||||
|
} else if let State::CONTROL_SOCKET_CONNECT = state {
|
||||||
|
if socket.may_send() {
|
||||||
|
socket.send_slice(&cookie).unwrap();
|
||||||
|
state = State::CONTROL_COOKIE_SENT;
|
||||||
|
}
|
||||||
|
} else if let State::CONTROL_COOKIE_SENT = state {
|
||||||
|
let mut recv = [0u8; 1];
|
||||||
|
if socket.may_recv() {
|
||||||
|
socket.recv_slice(&mut recv).unwrap();
|
||||||
|
if recv[0] == 9 {
|
||||||
|
// param exchange
|
||||||
|
// dword len
|
||||||
|
let len = json.len();
|
||||||
|
let mut len_data = [0u8; 4];
|
||||||
|
len_data[3] = len as u8;
|
||||||
|
socket.send_slice(&len_data).unwrap();
|
||||||
|
socket.send_slice(&json).unwrap();
|
||||||
|
state = State::JSON_CONFIG_SENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let State::JSON_CONFIG_SENT = state {
|
||||||
|
let mut recv = [0u8; 1];
|
||||||
|
if socket.may_recv() {
|
||||||
|
socket.recv_slice(&mut recv).unwrap();
|
||||||
|
if recv[0] == 10 {
|
||||||
|
// create streams
|
||||||
|
state = State::CREATE_STREAMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let State::DATA_COOKIE_SENT = state {
|
||||||
|
let mut recv = [0u8; 1];
|
||||||
|
if socket.may_recv() {
|
||||||
|
socket.recv_slice(&mut recv).unwrap();
|
||||||
|
if recv[0] == 1 {
|
||||||
|
// test start
|
||||||
|
state = State::TEST_START;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let State::TEST_START = state {
|
||||||
|
let mut recv = [0u8; 1];
|
||||||
|
if socket.may_recv() {
|
||||||
|
socket.recv_slice(&mut recv).unwrap();
|
||||||
|
if recv[0] == 2 {
|
||||||
|
// test running
|
||||||
|
state = State::TEST_RUNNING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !socket.is_open() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut socket = sockets.get::<TcpSocket>(tcp2_handle);
|
||||||
|
if let State::CREATE_STREAMS = state {
|
||||||
|
socket.connect(IpEndpoint::new(IpAddress::v4(10, 0, 0, 1), 5201),
|
||||||
|
IpEndpoint::new(IpAddress::v4(10, 0, 0, 2), 5202)).unwrap();
|
||||||
|
state = State::DATA_SOCKET_CONNECT;
|
||||||
|
} else if let State::DATA_SOCKET_CONNECT = state {
|
||||||
|
if socket.may_send() {
|
||||||
|
socket.send_slice(&cookie).unwrap();
|
||||||
|
state = State::DATA_COOKIE_SENT;
|
||||||
|
}
|
||||||
|
} else if let State::TEST_RUNNING = state {
|
||||||
|
if socket.can_send() {
|
||||||
|
socket.send_slice(&data).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if state != last_state {
|
||||||
|
println!("{:?} -> {:?}", last_state, state);
|
||||||
|
}
|
||||||
|
last_state = state;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue