portus 0.9.0

A Congestion Control Plane
Documentation
//! CCP sends this message containing a datapath program.

use super::{AsRawMsg, HDR_LENGTH, RawMsg, u32_to_u8s};
use crate::Result;
use crate::lang::Bin;
use std::io::prelude::*;

pub(crate) const INSTALL: u8 = 2;

#[derive(Clone, Debug, PartialEq)]
pub struct Msg {
    pub sid: u32,
    pub program_uid: u32,
    pub num_events: u32,
    pub num_instrs: u32,
    pub instrs: Bin,
}

impl AsRawMsg for Msg {
    fn get_hdr(&self) -> (u8, u32, u32) {
        (
            INSTALL,
            HDR_LENGTH + 12 + (self.num_events * 16 + self.num_instrs * 16),
            self.sid,
        )
    }

    fn get_u32s<W: Write>(&self, w: &mut W) -> Result<()> {
        let mut buf = [0u8; 4];
        u32_to_u8s(&mut buf, self.program_uid);
        w.write_all(&buf[..])?;
        u32_to_u8s(&mut buf, self.num_events);
        w.write_all(&buf[..])?;
        u32_to_u8s(&mut buf, self.num_instrs);
        w.write_all(&buf[..])?;
        Ok(())
    }

    fn get_bytes<W: Write>(&self, w: &mut W) -> Result<()> {
        let buf = self.instrs.serialize()?;
        w.write_all(&buf[..])?;
        Ok(())
    }

    // at least for now, portus doesn't have to worry about deserializing this
    fn from_raw_msg(_msg: RawMsg) -> Result<Self> {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use crate::lang::{Bin, Prog};

    #[test]
    fn serialize_install_msg() {
        let foo = "
        (def (Report (volatile foo 0)))
        (when true
            (bind Report.foo 4)
        )
        ";

        let (p, mut sc) = Prog::new_with_scope(foo).unwrap();
        let b = Bin::compile_prog(&p, &mut sc).unwrap();
        let m = super::Msg {
            sid: 1,
            program_uid: 7,
            num_events: 1,
            num_instrs: 3,
            instrs: b,
        };

        let buf: Vec<u8> =
            crate::serialize::serialize::<super::Msg>(&m.clone()).expect("serialize");
        assert_eq!(
            buf,
            vec![
                2, 0, // INSTALL
                84, 0, // length = 84
                1, 0, 0, 0, // sock_id = 1
                7, 0, 0, 0, // program_uid = 7
                1, 0, 0, 0, // num_events = 1
                3, 0, 0, 0, // num_instrs = 3
                1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0,
                0, // event { flag-idx=1, num-flag=1, body-idx=2, num-body=1 }
                2, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 0, 0, 0, 0, // (def (Report.foo 0))
                1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, // (when true
                1, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4, 0, 0, 0, //     (bind Report.foo 4))
            ],
        );
    }
}