use core::mem;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
pub struct Mpls {
pub lbl_tc_s: [u8; 3],
pub ttl: u8,
}
impl Mpls {
pub const LEN: usize = mem::size_of::<Mpls>();
#[inline]
pub fn label(&self) -> u32 {
let upper_bits = (self.lbl_tc_s[0] as u32) << 12;
let middle_bits = (self.lbl_tc_s[1] as u32) << 4;
let lower_bits = ((self.lbl_tc_s[2] & 0xF0) >> 4) as u32;
upper_bits | middle_bits | lower_bits
}
#[inline]
pub fn set_label(&mut self, label: u32) {
self.lbl_tc_s[0] = ((label >> 12) & 0xFF) as u8;
self.lbl_tc_s[1] = ((label >> 4) & 0xFF) as u8;
let preserved_bits = self.lbl_tc_s[2] & 0x0F;
self.lbl_tc_s[2] = ((label & 0x0F) << 4) as u8 | preserved_bits;
}
#[inline]
pub fn tc(&self) -> u8 {
(self.lbl_tc_s[2] & 0xE) >> 1
}
#[inline]
pub fn set_tc(&mut self, tc_value: u8) {
let preserved_bits = self.lbl_tc_s[2] & 0xF1;
self.lbl_tc_s[2] = preserved_bits | ((tc_value & 0x07) << 1);
}
#[inline]
pub fn s(&self) -> u8 {
self.lbl_tc_s[2] & 0x01
}
#[inline]
pub fn set_s(&mut self, s_value: u8) {
let preserved_bits = self.lbl_tc_s[2] & 0xFE;
self.lbl_tc_s[2] = preserved_bits | (s_value & 0x01);
}
#[inline]
pub fn ttl(&self) -> u8 {
self.ttl
}
#[inline]
pub fn set_ttl(&mut self, ttl_value: u8) {
self.ttl = ttl_value;
}
}
#[cfg(test)]
mod tests {
use super::*;
unsafe fn mpls_from_bytes(bytes: &[u8; Mpls::LEN]) -> &Mpls {
&*(bytes.as_ptr() as *const Mpls)
}
unsafe fn mpls_from_bytes_mut(bytes: &mut [u8; Mpls::LEN]) -> &mut Mpls {
&mut *(bytes.as_mut_ptr() as *mut Mpls)
}
#[test]
fn test_mpls_getters() {
let mpls_bytes: [u8; Mpls::LEN] = [0xAB, 0xCD, 0xEB, 0x40];
let mpls_header = unsafe { mpls_from_bytes(&mpls_bytes) };
assert_eq!(mpls_header.label(), 0xABCDE);
assert_eq!(mpls_header.tc(), 0x05); assert_eq!(mpls_header.s(), 0x01);
assert_eq!(mpls_header.ttl(), 0x40);
}
#[test]
fn test_mpls_set_label() {
let mut mpls_bytes: [u8; Mpls::LEN] = [0x00, 0x00, 0x00, 0x00];
let mpls_header = unsafe { mpls_from_bytes_mut(&mut mpls_bytes) };
mpls_header.set_label(0x12345);
assert_eq!(mpls_header.label(), 0x12345);
assert_eq!(mpls_bytes, [0x12, 0x34, 0x50, 0x00]);
mpls_bytes = [0xFF, 0xFF, 0x0F, 0xFF];
let mpls_header2 = unsafe { mpls_from_bytes_mut(&mut mpls_bytes) };
mpls_header2.set_label(0xABCDE);
assert_eq!(mpls_header2.label(), 0xABCDE);
assert_eq!(mpls_header2.tc(), 0x07); assert_eq!(mpls_header2.s(), 0x01); assert_eq!(mpls_bytes, [0xAB, 0xCD, 0xEF, 0xFF]);
}
#[test]
fn test_mpls_set_tc() {
let mut mpls_bytes: [u8; Mpls::LEN] = [0x00, 0x00, 0xA5, 0x00];
let mpls_header = unsafe { mpls_from_bytes_mut(&mut mpls_bytes) };
mpls_header.set_tc(0x06);
assert_eq!(mpls_header.tc(), 0x06);
assert_eq!(((mpls_bytes[2] & 0xF0) >> 4), 0x0A);
assert_eq!((mpls_bytes[2] & 0x01), 0x01);
assert_eq!(mpls_bytes, [0x00, 0x00, 0xAD, 0x00]);
}
#[test]
fn test_mpls_set_s() {
let mut mpls_bytes: [u8; Mpls::LEN] = [0x00, 0x00, 0xA6, 0x00];
let mpls_header = unsafe { mpls_from_bytes_mut(&mut mpls_bytes) };
mpls_header.set_s(0x01);
assert_eq!(mpls_header.s(), 0x01);
assert_eq!(((mpls_bytes[2] & 0xF0) >> 4), 0x0A); assert_eq!(((mpls_bytes[2] & 0x0E) >> 1), 0x03); assert_eq!(mpls_bytes, [0x00, 0x00, 0xA7, 0x00]);
}
#[test]
fn test_mpls_set_ttl() {
let mut mpls_bytes: [u8; Mpls::LEN] = [0x12, 0x34, 0x56, 0x00];
let mpls_header = unsafe { mpls_from_bytes_mut(&mut mpls_bytes) };
mpls_header.set_ttl(0xFF);
assert_eq!(mpls_header.ttl(), 0xFF);
assert_eq!(mpls_bytes, [0x12, 0x34, 0x56, 0xFF]);
}
}