ezpkt 0.4.0

A packet construction library
Documentation
use std::net::Ipv4Addr;

use pkt::erspan3::{erspan3_hdr, Erspan3, Erspan3Platform};
use pkt::eth::ethertype;
use pkt::gre::GreFlags;
use pkt::Packet;

use crate::GreFrame;

#[derive(Copy, Clone, Debug)]
pub struct Erspan3Frame {
    src: Ipv4Addr,
    dst: Ipv4Addr,
    raw: bool,
    erspan: Erspan3,
    seq: u32,
    platform: Option<Erspan3Platform>,
}

impl Erspan3Frame {
    pub const OVERHEAD: usize = std::mem::size_of::<erspan3_hdr>();
    pub const PLATFORM_OVERHEAD: usize = std::mem::size_of::<u64>();

    pub fn new(src: Ipv4Addr, dst: Ipv4Addr, raw: bool) -> Self {
        Self {
            src,
            dst,
            raw,
            erspan: Default::default(),
            seq: Default::default(),
            platform: None,
        }
    }

    pub fn raw(mut self, raw: bool) -> Self {
        self.raw = raw;
        self
    }

    pub fn src(mut self, src: Ipv4Addr) -> Self {
        self.src = src;
        self
    }

    pub fn dst(mut self, dst: Ipv4Addr) -> Self {
        self.dst = dst;
        self
    }

    pub fn erspan(mut self, erspan: Erspan3) -> Self {
        self.erspan = erspan;
        self
    }

    pub fn seq(mut self, seq: u32) -> Self {
        self.seq = seq;
        self
    }

    pub fn platform(mut self, platform: Erspan3Platform) -> Self {
        self.platform = Some(platform);
        self
    }

    pub fn encap<T: AsRef<[u8]>>(self, payload: T) -> Packet {
        let p = payload.as_ref();

        let overhead =
            Erspan3Frame::OVERHEAD + self.platform.map_or(0, |_| Erspan3Frame::PLATFORM_OVERHEAD);

        let mut erspan = self.erspan;
        if self.platform.is_some() {
            erspan = erspan.optional(true);
        }

        let gre = GreFrame::new(
            self.src,
            self.dst,
            GreFlags::default().seq(true),
            ethertype::ERSPAN_3,
            self.raw,
            overhead + p.len(),
        );

        let mut frame = gre.seq(self.seq).set_hdr(erspan.build());

        if let Some(plat) = self.platform {
            frame = frame.push(plat.to_be_bytes());
        }

        frame.push(payload).into()
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct Erspan3Flow {
    cl: Ipv4Addr,
    sv: Ipv4Addr,
    raw: bool,
    seq: u32,
    pub session_id: u16,
    pub hwid: u8,
    pub sgt: u16,
    pub ft: u8,
    pub gra: u8,
    pub d: bool,
    pub platform: Option<Erspan3Platform>,
}

impl Erspan3Flow {
    pub fn new(cl: Ipv4Addr, sv: Ipv4Addr, raw: bool) -> Self {
        Self {
            cl,
            sv,
            raw,
            seq: 0,
            session_id: 0,
            hwid: 0,
            sgt: 0,
            ft: 0,
            gra: 0,
            d: false,
            platform: None,
        }
    }

    fn next_seq(&mut self) -> u32 {
        let ret = self.seq;

        self.seq += 1;

        ret
    }

    fn dgram(&mut self) -> Erspan3Frame {
        let mut frame = Erspan3Frame::new(self.cl, self.sv, self.raw).seq(self.next_seq());
        if let Some(plat) = self.platform {
            frame = frame.platform(plat);
        }
        frame
    }

    fn erspan(&self) -> Erspan3 {
        Erspan3::default()
            .session_id(self.session_id)
            .hwid(self.hwid)
            .sgt(self.sgt)
            .ft(self.ft)
            .gra(self.gra)
            .direction(self.d)
    }

    pub fn encap(&mut self, bytes: &[u8], timestamp: u32) -> Packet {
        let flags = self.erspan().timestamp(timestamp);

        self.dgram().erspan(flags).encap(bytes)
    }
}