portus 0.9.0

A Congestion Control Plane
Documentation
//! Serialization library for communicating with libccp in the datapath.
//!
//! Messages have a common CCP header:
//!
//! ```text
//! -----------------------------------
//! | Msg Type | Len (B)  | Uint32    |
//! | (2 B)    | (2 B)    | (32 bits) |
//! -----------------------------------
//! total: 8 Bytes
//! ```
//!
//! Message types 0-3 are reserved for predefined message types. All other types are treated as
//! "unknown" - the header will be parsed, and raw access to the remaining bytes is available
//! through `RawMsg::get_bytes()`.
//!
//! A message type has 4 components, always in the following order.
//! 1. CCP Header
//! 2. u32s
//! 3. u64s
//! 4. Arbitrary bytes
//!
//! For convenience, the predefined message types define a number of u32s and u64s.
//! External message types can implement `get_bytes()` to pass custom types in the message payload.
//! In these cases, there is little deserialization overhead from the u32 and u64 parts of the message.

use super::Result;
use byteorder::{ByteOrder, LittleEndian};
use std::io::Cursor;
use std::io::prelude::*;
use std::vec::Vec;
use tracing::debug;

fn u16_to_u8s(buf: &mut [u8], num: u16) {
    LittleEndian::write_u16(buf, num);
}

pub(crate) fn u32_to_u8s(buf: &mut [u8], num: u32) {
    LittleEndian::write_u32(buf, num);
}

pub(crate) fn u64_to_u8s(buf: &mut [u8], num: u64) {
    LittleEndian::write_u64(buf, num);
}

fn u16_from_u8s(buf: &[u8]) -> u16 {
    LittleEndian::read_u16(buf)
}

pub(crate) fn u32_from_u8s(buf: &[u8]) -> u32 {
    LittleEndian::read_u32(buf)
}

pub(crate) fn u64_from_u8s(buf: &[u8]) -> u64 {
    LittleEndian::read_u64(buf)
}

pub const HDR_LENGTH: u32 = 8;
fn serialize_header(typ: u8, len: u32, sid: u32) -> Vec<u8> {
    let mut hdr = [0u8; 8];
    u16_to_u8s(&mut hdr[0..2], u16::from(typ));
    u16_to_u8s(&mut hdr[2..4], len as u16);
    u32_to_u8s(&mut hdr[4..], sid);
    hdr.to_vec()
}

fn deserialize_header<R: Read>(buf: &mut R) -> Result<(u8, u32, u32)> {
    let mut hdr = [0u8; 8];
    buf.read_exact(&mut hdr)?;
    let typ = u16_from_u8s(&hdr[0..2]);
    let len = u16_from_u8s(&hdr[2..4]);
    let sid = u32_from_u8s(&hdr[4..]);

    Ok((typ as u8, u32::from(len), sid))
}

#[derive(Clone, Debug, PartialEq)]
/// A raw messge buffer with a parsed CCP header.
pub struct RawMsg<'a> {
    pub typ: u8,
    pub len: u32,
    pub sid: u32,
    bytes: &'a [u8],
}

impl<'a> RawMsg<'a> {
    /// For predefined messages, get u32s separately for convenience
    pub(crate) unsafe fn get_u32s(&self) -> Result<&'a [u32]> {
        unsafe {
            use std::mem;
            match self.typ {
                create::CREATE => Ok(mem::transmute(&self.bytes[0..(4 * 6)])),
                measure::MEASURE => Ok(mem::transmute(&self.bytes[0..8])),
                update_field::UPDATE_FIELD => Ok(mem::transmute(&self.bytes[0..4])),
                ready::READY => Ok(mem::transmute(&self.bytes[0..(4 * 1)])),
                _ => Ok(&[]),
            }
        }
    }

    /// For predefined messages, bytes blob is whatever's left (may be nothing)
    /// For other message types, just return the bytes blob
    pub fn get_bytes(&self) -> Result<&'a [u8]> {
        match self.typ {
            create::CREATE => Ok(&self.bytes[(4 * 6)..(self.len as usize - HDR_LENGTH as usize)]),
            measure::MEASURE => Ok(&self.bytes[8..(self.len as usize - HDR_LENGTH as usize)]),
            update_field::UPDATE_FIELD => {
                Ok(&self.bytes[4..(self.len as usize - HDR_LENGTH as usize)])
            }
            _ => Ok(self.bytes),
        }
    }
}

/// Types that can be serialized.
// Message types wanting to become "predefined" (and as such take advantage of `get_u32s()` and
// `get_u64s()` below) should edit this file accordingly (see `impl RawMsg`)
pub trait AsRawMsg {
    fn get_hdr(&self) -> (u8, u32, u32);
    fn get_u32s<W: Write>(&self, _: &mut W) -> Result<()> {
        Ok(())
    }

    fn get_u64s<W: Write>(&self, _: &mut W) -> Result<()> {
        Ok(())
    }

    fn get_bytes<W: Write>(&self, w: &mut W) -> Result<()>;
    fn from_raw_msg(msg: RawMsg) -> Result<Self>
    where
        Self: std::marker::Sized;
}

#[macro_use]
mod test_helper {
    /// Generates a test which serializes and deserializes a message
    /// and verifies the message is unchanged.
    #[macro_export]
    macro_rules! check_msg {
        ($id: ident, $typ: ty, $m: expr_2021, $got: pat, $x: ident) => {
            #[test]
            fn $id() {
                let m = $m;
                let buf: Vec<u8> =
                    crate::serialize::serialize::<$typ>(&m.clone()).expect("serialize");
                let (msg, _) =
                    $crate::serialize::Msg::from_buf(&buf[..]).expect("deserialize: check_msg");
                match msg {
                    $got => assert_eq!($x, m),
                    _ => panic!("wrong type for message"),
                }
            }
        };
    }
}

pub mod changeprog;
pub mod create;
pub mod install;
pub mod measure;
pub mod ready;
pub mod update_field;

/// Serialize a serializable message.
pub fn serialize<T: AsRawMsg>(m: &T) -> Result<Vec<u8>> {
    let (a, b, c) = m.get_hdr();
    let mut msg = serialize_header(a, b, c);
    m.get_u32s(&mut msg)?;
    m.get_u64s(&mut msg)?;
    m.get_bytes(&mut msg)?;
    Ok(msg)
}

fn deserialize(buf: &[u8]) -> Result<RawMsg<'_>> {
    let mut buf = Cursor::new(buf);
    let (typ, len, sid) = deserialize_header(&mut buf)?;
    if len < 8 {
        return Err(super::Error(format!(
            "nonsensical len in header: ({}, {}, {})",
            typ, len, sid
        )));
    }
    if len > buf.get_ref().len() as u32 {
        return Err(super::Error(format!(
            "header len claims {} but buf size is {}",
            len,
            buf.get_ref().len()
        )));
    }

    let i = buf.position();
    Ok(RawMsg {
        typ,
        len,
        sid,
        bytes: &buf.into_inner()[i as usize..(len as usize)],
    })
}

/// Message type for deserialization.
/// Reads message type in the header of the input buffer and returns
/// a Msg of the corresponding type. If the message type is unkown, returns a
/// wrapper with direct access to the message bytes.
#[derive(Debug, PartialEq)]
pub enum Msg<'a> {
    Cr(create::Msg),
    Ms(measure::Msg),
    Ins(install::Msg),
    Rdy(ready::Msg),
    Other(RawMsg<'a>),
}

impl<'a> Msg<'a> {
    fn from_raw_msg(m: RawMsg) -> Result<Msg> {
        match m.typ {
            create::CREATE => Ok(Msg::Cr(create::Msg::from_raw_msg(m)?)),
            measure::MEASURE => Ok(Msg::Ms(measure::Msg::from_raw_msg(m)?)),
            install::INSTALL => Ok(Msg::Ins(install::Msg::from_raw_msg(m)?)),
            ready::READY => Ok(Msg::Rdy(ready::Msg::from_raw_msg(m)?)),
            update_field::UPDATE_FIELD => unimplemented!(),
            _ => Ok(Msg::Other(m)),
        }
    }

    pub fn from_buf(buf: &[u8]) -> Result<(Msg<'_>, usize)> {
        deserialize(buf)
            .map_or_else(
                |e| {
                    debug!(err = %format!("{:#?}", e), "failed deserialization");
                    Ok((
                        RawMsg {
                            typ: 255,
                            len: 0,
                            sid: 0,
                            bytes: &buf,
                        },
                        buf.len(),
                    ))
                },
                |m| {
                    let len = m.len;
                    Ok((m, len as usize))
                },
            )
            .and_then(|(m, l)| Ok((Msg::from_raw_msg(m)?, l)))
    }
}

#[cfg(test)]
mod testmsg;
#[cfg(test)]
mod tests {
    #[test]
    fn test_from_u16() {
        let mut buf = [0u8; 2];
        let x: u16 = 2;
        super::u16_to_u8s(&mut buf, x);
        assert_eq!(buf, [0x2, 0x0]);
    }

    #[test]
    fn test_from_u32() {
        let mut buf = [0u8; 4];
        let x: u32 = 42;
        super::u32_to_u8s(&mut buf, x);
        assert_eq!(buf, [0x2A, 0, 0, 0]);
    }

    #[test]
    fn test_from_u64() {
        let mut buf = [0u8; 8];
        let x: u64 = 42;
        super::u64_to_u8s(&mut buf, x);
        assert_eq!(buf, [0x2A, 0, 0, 0, 0, 0, 0, 0]);

        let x: u64 = 42424242;
        super::u64_to_u8s(&mut buf, x);
        assert_eq!(buf, [0xB2, 0x57, 0x87, 0x02, 0, 0, 0, 0]);
    }

    #[test]
    fn test_to_u16() {
        let buf = vec![0x3, 0];
        let x = super::u16_from_u8s(&buf[..]);
        assert_eq!(x, 3);
    }

    #[test]
    fn test_to_u32() {
        let buf = vec![0x2A, 0, 0, 0];
        let x = super::u32_from_u8s(&buf[..]);
        assert_eq!(x, 42);

        let buf = vec![0x42, 0, 0x42, 0];
        let x = super::u32_from_u8s(&buf[..]);
        assert_eq!(x, 4325442);
    }

    #[test]
    fn test_to_u64_0() {
        let buf = vec![0x42, 0, 0x42, 0, 0, 0, 0, 0];
        let x = super::u64_from_u8s(&buf[..]);
        assert_eq!(x, 4325442);
    }

    #[test]
    fn test_to_u64_1() {
        let buf = vec![0, 0x42, 0, 0x42, 0, 0x42, 0, 0x42];
        let x = super::u64_from_u8s(&buf[..]);
        assert_eq!(x, 4755873775377990144);
    }

    #[test]
    fn test_other_msg() {
        use super::AsRawMsg;
        use super::testmsg;
        let m = testmsg::Msg(String::from("testing"));
        let buf: Vec<u8> = super::serialize::<testmsg::Msg>(&m.clone()).expect("serialize");
        let (msg, _) = super::Msg::from_buf(&buf[..]).expect("deserialize");
        match msg {
            super::Msg::Other(raw) => {
                let got = testmsg::Msg::from_raw_msg(raw).expect("get raw msg");
                assert_eq!(m, got);
            }
            _ => panic!("wrong type for message"),
        }
    }

    #[test]
    fn test_multi_msg() {
        use super::AsRawMsg;
        use super::testmsg;

        let m1 = testmsg::Msg(String::from("foo"));
        let m2 = testmsg::Msg(String::from("bar"));
        let mut buf: Vec<u8> = super::serialize::<testmsg::Msg>(&m1.clone()).expect("serialize");
        buf.extend(super::serialize::<testmsg::Msg>(&m2.clone()).expect("serialize"));

        let (msg, len1) = super::Msg::from_buf(&buf[..]).expect("deserialize");
        match msg {
            super::Msg::Other(raw) => {
                let got = testmsg::Msg::from_raw_msg(raw).expect("get raw msg");
                assert_eq!(m1, got);
            }
            _ => panic!("wrong type for message"),
        }

        let (msg, len2) = super::Msg::from_buf(&buf[len1..]).expect("deserialize");
        match msg {
            super::Msg::Other(raw) => {
                let got = testmsg::Msg::from_raw_msg(raw).expect("get raw msg");
                assert_eq!(m2, got);
            }
            _ => panic!("wrong type for message"),
        }

        assert_eq!(buf[len1 + len2..].len(), 0);
    }
}