#![recursion_limit = "512"]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(unused)]
mod ccp;
extern crate failure;
use failure::bail;
#[macro_use]
extern crate mashup;
extern crate time;
pub trait DatapathOps {
fn send_msg(&mut self, msg: &[u8]);
fn log(&self, _level: ccp::ccp_log_level, _msg: &str) {}
}
struct DatapathObj(Box<DatapathOps>);
pub struct Datapath(i8);
impl Datapath {
pub fn init<T: DatapathOps + 'static>(dp: T) -> Result<Self, failure::Error> {
let dp = Box::new(DatapathObj(Box::new(dp)));
let mut dp = ccp::ccp_datapath {
set_cwnd: Some(ccp::set_cwnd),
set_rate_abs: Some(ccp::set_rate_abs),
time_zero: time::precise_time_ns(),
now: Some(ccp::now),
since_usecs: Some(ccp::since_usecs),
after_usecs: Some(ccp::after_usecs),
send_msg: Some(ccp::send_msg),
log: Some(ccp::log),
state: std::ptr::null_mut(),
impl_: Box::into_raw(dp) as *mut std::os::raw::c_void,
};
let ok = unsafe { ccp::ccp_init(&mut dp) };
match ok {
i if i >= 0 => (),
-1 => unreachable!(),
-2 => bail!("Cannot initialize libccp twice"),
-3 | -4 | -5 => bail!("Could not alloc"),
i if i < -5 => unreachable!(),
_ => unreachable!(),
};
Ok(Datapath(0))
}
pub fn recv_msg(&self, msg: &mut [u8]) -> Result<(), failure::Error> {
let buf_len = msg.len();
let ok = unsafe {
ccp::ccp_read_msg(
msg.as_mut_ptr() as *mut std::os::raw::c_char,
buf_len as i32,
)
};
if ok < 0 {
bail!("ccp_read_msg failed with {:?}", ok);
}
Ok(())
}
}
impl Drop for Datapath {
fn drop(&mut self) {
unsafe { ccp::ccp_free() }
}
}
pub trait CongestionOps {
fn set_cwnd(&mut self, cwnd: u32);
fn set_rate_abs(&mut self, rate: u32);
}
impl CongestionOps {
fn downcast<T: CongestionOps>(&self) -> &T {
unsafe { &*(self as *const Self as *const T) }
}
fn downcast_mut<T: CongestionOps>(&mut self) -> &mut T {
unsafe { &mut *(self as *mut Self as *mut T) }
}
}
struct ConnectionObj(Box<dyn CongestionOps>);
macro_rules! setters {
( $s:ident => $($x: ident : $t: ty),+ ) => {
mashup! { $(
m["fname" $x] = with_ $x;
)* }
m! { impl $s { $(
pub fn "fname" $x (mut self, val: $t) -> Self { (self.0).$x = val; self }
)*
} }
};
}
mod flow_info;
mod primitives;
pub use crate::flow_info::FlowInfo;
pub use crate::primitives::Primitives;
pub struct Connection<'dp, T: CongestionOps + 'static>(
*mut ccp::ccp_connection,
Box<ConnectionObj>,
&'dp Datapath,
std::marker::PhantomData<T>,
);
impl<'dp, T: CongestionOps + 'static> Connection<'dp, T> {
pub fn start(
token: &'dp Datapath,
conn: T,
flow_info: FlowInfo,
) -> Result<Self, failure::Error> {
if token.0 != 0 {
unreachable!();
}
let conn_obj = Box::new(ConnectionObj(Box::new(conn) as Box<dyn CongestionOps>));
let ops_raw_pointer = Box::into_raw(conn_obj);
let conn_obj = unsafe { Box::from_raw(ops_raw_pointer.clone()) };
let conn = unsafe {
ccp::ccp_connection_start(
Box::into_raw(conn_obj) as *mut std::os::raw::c_void,
&mut flow_info.get_dp_info(),
)
};
if conn.is_null() {
bail!("Could not initialize connection");
}
Ok(Connection(
conn,
unsafe { Box::from_raw(ops_raw_pointer) },
token,
Default::default(),
))
}
pub fn load_primitives(&mut self, prims: Primitives) {
unsafe {
(*(self.0)).prims = prims.0;
}
}
pub fn primitives(&self, _token: &Datapath) -> Primitives {
let pr = unsafe { &(*(self.0)).prims };
pr.into()
}
pub fn invoke(&mut self) -> Result<(), failure::Error> {
let ok = unsafe { ccp::ccp_invoke(self.0) };
if ok < 0 {
bail!("CCP Invoke error: {:?}", ok);
}
Ok(())
}
}
unsafe impl<'dp, T: CongestionOps> Send for Connection<'dp, T> {}
impl<'dp, T: CongestionOps> Drop for Connection<'dp, T> {
fn drop(&mut self) {
unsafe {
let index = (*(self.0)).index;
ccp::ccp_connection_free(index);
}
}
}
impl<'dp, T: CongestionOps> std::ops::Deref for Connection<'dp, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
let y = &*(self.1);
y.0.downcast::<T>()
}
}
impl<'dp, T: CongestionOps> std::ops::DerefMut for Connection<'dp, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
let y = &mut *(self.1);
y.0.downcast_mut::<T>()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Dp {
expected_msgs: Vec<Option<Vec<u8>>>,
}
impl DatapathOps for Dp {
fn send_msg(&mut self, msg: &[u8]) {
if self.expected_msgs.is_empty() {
return;
}
let expected_send_msg: Vec<u8> = self.expected_msgs.pop().unwrap().unwrap();
println!(
"this message: {:?}, remaining messsages: {:?}",
expected_send_msg, self.expected_msgs
);
assert_eq!(msg, &expected_send_msg[..msg.len()]);
}
}
struct Cn {
curr_cwnd: u32,
curr_rate: u32,
}
impl CongestionOps for Cn {
fn set_cwnd(&mut self, cwnd: u32) {
self.curr_cwnd = cwnd;
}
fn set_rate_abs(&mut self, rate: u32) {
self.curr_rate = rate;
}
}
fn make_dp(expected_msgs: Vec<Option<Vec<u8>>>) -> Datapath {
let dp = Dp { expected_msgs };
Datapath::init(dp).unwrap()
}
fn make_conn(d: &Datapath) -> Connection<Cn> {
let cn = Cn {
curr_cwnd: 19,
curr_rate: 89,
};
let fi = FlowInfo::default()
.with_init_cwnd(100)
.with_mss(10)
.with_four_tuple(1, 2, 3, 4);
let c = Connection::start(d, cn, fi).unwrap();
assert_eq!(c.curr_cwnd, 19);
c
}
use lazy_static::lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
}
#[test]
fn primitives() {
let _l = TEST_MUTEX.lock().unwrap();
let prims_prog_uid = 5;
#[rustfmt::skip]
let dp = make_dp(vec![
Some(vec![
0x01, 0,
16, 0,
0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
]),
Some(vec![
0x01, 0x00,
0x18, 0x00,
0x01, 0x00, 0x00, 0x00,
prims_prog_uid, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]),
Some(vec![
0x00,0x00,
0x20,0x00,
0x01,0x00,0x00,0x00,
0x64,0x00,0x00,0x00,
0x0a,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,
0x03,0x00,0x00,0x00,
0x04,0x00,0x00,0x00,
]),
]);
let mut c = make_conn(&dp);
#[rustfmt::skip]
let mut install_prims = vec![
2, 0,
116, 0,
1, 0, 0, 0,
prims_prog_uid, 0, 0, 0,
1, 0, 0, 0,
5, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
2, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0, 0, 0, 0,
1, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0,
1, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 1, 1, 0, 0, 0,
];
#[rustfmt::skip]
let mut changeprog_msg = vec![
4, 0,
12, 0,
1, 0, 0, 0,
prims_prog_uid, 0, 0, 0,
0, 0, 0, 0,
];
dp.recv_msg(&mut install_prims).unwrap();
dp.recv_msg(&mut changeprog_msg).unwrap();
c.load_primitives(
Primitives::default()
.with_bytes_acked(1)
.with_rtt_sample_us(100),
);
c.invoke().unwrap();
}
#[test]
fn primitives_multiple() {
let _l = TEST_MUTEX.lock().unwrap();
let prims_prog_uid = 5;
#[rustfmt::skip]
let close =
Some(vec![
0x01, 0,
16, 0,
0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
]);
#[rustfmt::skip]
let report =
Some(vec![
0x01, 0x00,
0x18, 0x00,
0x01, 0x00, 0x00, 0x00,
prims_prog_uid, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);
#[rustfmt::skip]
let create =
Some(vec![
0x00,0x00,
0x20,0x00,
0x01,0x00,0x00,0x00,
0x64,0x00,0x00,0x00,
0x0a,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,
0x03,0x00,0x00,0x00,
0x04,0x00,0x00,0x00,
]);
let mut msgs = vec![close];
msgs.push(report.clone());
msgs.push(report.clone());
msgs.push(report.clone());
msgs.push(report);
msgs.push(create);
let dp = make_dp(msgs);
let mut c = make_conn(&dp);
#[rustfmt::skip]
let mut install_prims = vec![
2, 0,
116, 0,
1, 0, 0, 0,
prims_prog_uid, 0, 0, 0,
1, 0, 0, 0,
5, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
2, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0, 0, 0, 0,
1, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0,
1, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 1, 1, 0, 0, 0,
];
#[rustfmt::skip]
let mut changeprog_msg = vec![
4, 0,
12, 0,
1, 0, 0, 0,
prims_prog_uid, 0, 0, 0,
0, 0, 0, 0,
];
dp.recv_msg(&mut install_prims).unwrap();
dp.recv_msg(&mut changeprog_msg).unwrap();
for _ in 0..4 {
c.load_primitives(
Primitives::default()
.with_bytes_acked(1)
.with_rtt_sample_us(100),
);
c.invoke().unwrap();
}
}
#[test]
fn basic() {
let _l = TEST_MUTEX.lock().unwrap();
let basic_prog_uid = 4;
#[rustfmt::skip]
let dp = make_dp(vec![
Some(vec![
0x01, 0,
16, 0,
0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
]),
Some(vec![
0x01, 0x00,
0x18, 0x00,
0x01, 0x00, 0x00, 0x00,
basic_prog_uid, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]),
Some(vec![
0x00,0x00,
0x20,0x00,
0x01,0x00,0x00,0x00,
0x64,0x00,0x00,0x00,
0x0a,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,
0x03,0x00,0x00,0x00,
0x04,0x00,0x00,0x00,
]),
]);
let mut c = make_conn(&dp);
#[rustfmt::skip]
let mut install_basic = vec![
2, 0,
116, 0,
1, 0, 0, 0,
basic_prog_uid, 0, 0, 0,
1, 0, 0, 0,
5, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
2, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 1, 0, 0, 0,
1, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0,
1, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 1, 1, 0, 0, 0,
];
#[rustfmt::skip]
let mut changeprog_msg = vec![
4, 0,
12, 0,
1, 0, 0, 0,
basic_prog_uid, 0, 0, 0,
0, 0, 0, 0,
];
dp.recv_msg(&mut install_basic).unwrap();
dp.recv_msg(&mut changeprog_msg).unwrap();
c.invoke().unwrap();
}
}