#![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 Datapath {
fn send_msg(&mut self, msg: &[u8]);
}
struct DatapathObj(Box<Datapath>);
pub fn recv_msg(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(())
}
pub fn init_with_datapath<T: Datapath + 'static>(dp: T) -> Result<(), 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),
set_rate_rel: Some(ccp::set_rate_rel),
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),
impl_: Box::into_raw(dp) as *mut std::os::raw::c_void,
};
let ok = unsafe { ccp::ccp_init(&mut dp) };
if ok < 0 {
bail!("Could not initialize ccp datapath");
}
Ok(())
}
pub fn deinit() {
unsafe { ccp::ccp_free() }
}
pub trait CongestionOps {
fn set_cwnd(&mut self, cwnd: u32);
fn set_rate_abs(&mut self, rate: u32);
}
struct ConnectionObj(Box<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(*mut ccp::ccp_connection);
impl Connection {
pub fn start(conn: Box<CongestionOps>, flow_info: FlowInfo) -> Result<Self, failure::Error> {
let conn_obj = Box::new(ConnectionObj(conn));
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))
}
pub fn end(self) {
unsafe {
let index = (*(self.0)).index;
ccp::ccp_connection_free(index);
}
}
pub fn load_primitives(&mut self, prims: Primitives) {
unsafe {
(*(self.0)).prims = prims.0;
}
}
pub fn primitives(&self) -> 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(())
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Dp {
expected_msgs: Vec<Option<Vec<u8>>>,
}
impl Datapath for Dp {
fn send_msg(&mut self, msg: &[u8]) {
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>>>) {
let dp = Dp { expected_msgs };
init_with_datapath(dp).unwrap();
}
fn free_dp() {
deinit()
}
fn make_conn() -> Connection {
let cn = Cn {
curr_cwnd: 0,
curr_rate: 0,
};
let fi = FlowInfo::default()
.with_init_cwnd(100)
.with_mss(10)
.with_four_tuple(1, 2, 3, 4);
Connection::start(Box::new(cn), fi).unwrap()
}
#[test]
fn basic() {
let basic_prog_uid = 4;
#[rustfmt::skip]
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();
#[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,
];
recv_msg(&mut install_basic).unwrap();
recv_msg(&mut changeprog_msg).unwrap();
c.invoke();
c.end();
free_dp();
return;
}
}