Skip to content

Commit

Permalink
[catpowder] Feature: XDP LibOS
Browse files Browse the repository at this point in the history
  • Loading branch information
ppenna committed Jun 17, 2024
1 parent 19e2a24 commit 8cdbcf9
Show file tree
Hide file tree
Showing 11 changed files with 934 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/rust/catpowder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ mod linux;

#[cfg(target_os = "linux")]
pub use linux::LinuxRuntime as CatpowderRuntime;

#[cfg(target_os = "windows")]
mod win;

#[cfg(target_os = "windows")]
pub use win::runtime::CatpowderRuntime;
70 changes: 70 additions & 0 deletions src/rust/catpowder/win/buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

//======================================================================================================================
// Imports
//======================================================================================================================

use crate::catpowder::win::umemreg::UmemReg;
use ::std::ops::{
Deref,
DerefMut,
};

//======================================================================================================================
// Structures
//======================================================================================================================

pub struct XdpBuffer {
b: *mut xdp_rs::XSK_BUFFER_DESCRIPTOR,
umemreg: UmemReg,
}

//======================================================================================================================
// Implementations
//======================================================================================================================

impl XdpBuffer {
pub fn new(b: *mut xdp_rs::XSK_BUFFER_DESCRIPTOR, umemreg: UmemReg) -> Self {
Self { b, umemreg }
}

pub fn len(&self) -> usize {
unsafe { (*self.b).Length as usize }
}

pub fn set_len(&mut self, len: usize) {
unsafe {
(*self.b).Length = len as u32;
}
}

unsafe fn base_address(&self) -> u64 {
(*self.b).Address.__bindgen_anon_1.BaseAddress()
}

unsafe fn offset(&self) -> u64 {
(*self.b).Address.__bindgen_anon_1.Offset()
}

unsafe fn addr(&self) -> *mut core::ffi::c_void {
let mut ptr: *mut u8 = self.umemreg.get_address() as *mut u8;
ptr = ptr.add(self.base_address() as usize);
ptr = ptr.add(self.offset() as usize);
ptr as *mut core::ffi::c_void
}
}

impl Deref for XdpBuffer {
type Target = [u8];

fn deref(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.addr() as *const u8, self.len()) }
}
}

impl DerefMut for XdpBuffer {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.addr() as *mut u8, self.len()) }
}
}
12 changes: 12 additions & 0 deletions src/rust/catpowder/win/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

mod buffer;
mod params;
mod program;
mod rule;
pub mod runtime;
mod rx_ring;
mod socket;
mod tx_ring;
mod umemreg;
37 changes: 37 additions & 0 deletions src/rust/catpowder/win/params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

//======================================================================================================================
// Imports
//======================================================================================================================

use crate::catpowder::win::socket::XdpSocket;
use ::std::mem;

//======================================================================================================================
// Structures
//======================================================================================================================

pub struct XdpRedirectParams {
redirect: xdp_rs::XDP_REDIRECT_PARAMS,
}

//======================================================================================================================
// Implementations
//======================================================================================================================

impl XdpRedirectParams {
pub fn new(socket: &XdpSocket) -> Self {
let redirect: xdp_rs::XDP_REDIRECT_PARAMS = {
let mut redirect: xdp_rs::_XDP_REDIRECT_PARAMS = unsafe { mem::zeroed() };
redirect.TargetType = xdp_rs::_XDP_REDIRECT_TARGET_TYPE_XDP_REDIRECT_TARGET_TYPE_XSK;
redirect.Target = socket.socket;
redirect
};
Self { redirect }
}

pub fn as_ptr(&self) -> &xdp_rs::XDP_REDIRECT_PARAMS {
&self.redirect
}
}
27 changes: 27 additions & 0 deletions src/rust/catpowder/win/program.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

//======================================================================================================================
// Imports
//======================================================================================================================

use ::windows::Win32::Foundation::HANDLE;

//======================================================================================================================
// Structures
//======================================================================================================================

#[derive(Default)]
pub struct XdpProgram {
program: HANDLE,
}

//======================================================================================================================
// Implementations
//======================================================================================================================

impl XdpProgram {
pub fn as_ptr(&mut self) -> *mut HANDLE {
&mut self.program as *mut HANDLE
}
}
46 changes: 46 additions & 0 deletions src/rust/catpowder/win/rule.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

//======================================================================================================================
// Imports
//======================================================================================================================

use crate::catpowder::win::{
params::XdpRedirectParams,
socket::XdpSocket,
};
use ::std::mem;

//======================================================================================================================
// Structures
//======================================================================================================================

pub struct XdpRule {
rule: xdp_rs::XDP_RULE,
}

//======================================================================================================================
// Implementations
//======================================================================================================================

impl XdpRule {
pub fn new(socket: &XdpSocket) -> Self {
let redirect: XdpRedirectParams = XdpRedirectParams::new(socket);
let rule: xdp_rs::XDP_RULE = unsafe {
let mut rule: xdp_rs::XDP_RULE = std::mem::zeroed();
rule.Match = xdp_rs::_XDP_MATCH_TYPE_XDP_MATCH_ALL;
rule.Action = xdp_rs::_XDP_RULE_ACTION_XDP_PROGRAM_ACTION_REDIRECT;
// TODO: Set pattern
// Perform bitwise copy from redirect to rule.
rule.__bindgen_anon_1 =
mem::transmute_copy::<xdp_rs::XDP_REDIRECT_PARAMS, xdp_rs::_XDP_RULE__bindgen_ty_1>(redirect.as_ptr());

rule
};
Self { rule }
}

pub fn as_ptr(&self) -> *const xdp_rs::XDP_RULE {
&self.rule
}
}
156 changes: 156 additions & 0 deletions src/rust/catpowder/win/runtime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

//======================================================================================================================
// Imports
//======================================================================================================================

use crate::{
catpowder::win::{
buffer::XdpBuffer,
rx_ring::RxRing,
socket::XdpApi,
tx_ring::TxRing,
},
demikernel::config::Config,
expect_ok,
runtime::{
fail::Fail,
memory::{
DemiBuffer,
MemoryRuntime,
},
network::{
consts::RECEIVE_BATCH_SIZE,
NetworkRuntime,
PacketBuf,
},
Runtime,
SharedObject,
},
};
use ::arrayvec::ArrayVec;
use ::std::borrow::{
Borrow,
BorrowMut,
};

//======================================================================================================================
// Structures
//======================================================================================================================

struct CatpowderRuntimeInner {
tx: TxRing,
rx: RxRing,
}
/// Underlying network transport.
#[derive(Clone)]
pub struct CatpowderRuntime {
api: XdpApi,
inner: SharedObject<CatpowderRuntimeInner>,
}

/// A network transport built on top of Windows XDP.
#[derive(Clone)]
pub struct SharedXdpTransport(SharedObject<CatpowderRuntime>);

//======================================================================================================================
// Associated Functions
//======================================================================================================================
impl CatpowderRuntime {}

impl NetworkRuntime for CatpowderRuntime {
fn new(igconfig: &Config) -> Result<Self, Fail> {
trace!("Creating XDP runtime.");
let mut api: XdpApi = XdpApi::new()?;

// TODO: read the following from the config file.
let index: u32 = 5;
let queueid: u32 = 0;

let rx: RxRing = RxRing::new(&mut api, index, queueid)?;
let tx: TxRing = TxRing::new(&mut api, index, queueid)?;

Ok(Self {
api,
inner: SharedObject::new(CatpowderRuntimeInner { rx, tx }),
})
}

fn transmit(&mut self, pkt: Box<dyn PacketBuf>) {
let header_size: usize = pkt.header_size();
let body_size: usize = pkt.body_size();
assert!(header_size + body_size < u16::MAX as usize);
trace!("header_size={:?}, body_size={:?}", header_size, body_size);

const COUNT: u32 = 1;
let mut idx: u32 = 0;

assert!(self.inner.borrow_mut().tx.producer_reserve(COUNT, &mut idx) == COUNT);

let mut buf: XdpBuffer = self.inner.borrow_mut().tx.get_element(idx);
buf.set_len(header_size + body_size);

pkt.write_header(&mut buf[..header_size]);
if let Some(body) = pkt.take_body() {
buf[header_size..].copy_from_slice(&body[..]);
}

self.inner.borrow_mut().tx.producer_submit(COUNT);

// Notify socket.
let mut outflags = xdp_rs::XSK_NOTIFY_RESULT_FLAGS::default();
self.inner
.borrow()
.tx
.notify_socket(
&mut self.api,
xdp_rs::_XSK_NOTIFY_FLAGS_XSK_NOTIFY_FLAG_POKE_TX | xdp_rs::_XSK_NOTIFY_FLAGS_XSK_NOTIFY_FLAG_WAIT_TX,
u32::MAX,
&mut outflags,
)
.unwrap();

if self.inner.borrow_mut().tx.consumer_reserve(COUNT, &mut idx) == COUNT {
self.inner.borrow_mut().tx.consumer_release(COUNT);
return;
}

warn!("failed to send packet");
}

fn receive(&mut self) -> ArrayVec<DemiBuffer, RECEIVE_BATCH_SIZE> {
let mut ret: ArrayVec<DemiBuffer, RECEIVE_BATCH_SIZE> = ArrayVec::new();
const COUNT: u32 = 1;
let mut idx: u32 = 0;

if self.inner.borrow_mut().rx.consumer_reserve(COUNT, &mut idx) == COUNT {
let xdpbuf: XdpBuffer = self.inner.borrow().rx.get_element(idx);
let mut out: Vec<u8> = Vec::with_capacity(xdpbuf.len());

xdpbuf[..].clone_into(&mut out);

let dbuf: DemiBuffer = expect_ok!(DemiBuffer::from_slice(&out), "'bytes' should fit");

ret.push(dbuf);

self.inner.borrow_mut().rx.consumer_release(COUNT);

self.inner.borrow_mut().rx.producer_reserve(COUNT, &mut idx);

self.inner.borrow_mut().rx.producer_submit(COUNT);
}

ret
}
}

//======================================================================================================================
// Trait Implementations
//======================================================================================================================

/// Memory runtime trait implementation for XDP Runtime.
impl MemoryRuntime for CatpowderRuntime {}

/// Runtime trait implementation for XDP Runtime.
impl Runtime for CatpowderRuntime {}
Loading

0 comments on commit 8cdbcf9

Please sign in to comment.