use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, FromBytes, IntoBytes, Immutable, KnownLayout)]
pub struct MplsLabelEntry {
pub entry: u32,
}
impl MplsLabelEntry {
pub const SIZE: usize = std::mem::size_of::<Self>();
pub fn new(label: u32) -> Self {
Self {
entry: ((label & 0xFFFFF) << 12).to_be(),
}
}
pub fn bottom(label: u32, ttl: u8) -> Self {
let entry = ((label & 0xFFFFF) << 12) | (1 << 8) | (ttl as u32);
Self {
entry: entry.to_be(),
}
}
pub fn with_fields(label: u32, tc: u8, bos: bool, ttl: u8) -> Self {
let entry = ((label & 0xFFFFF) << 12)
| (((tc & 0x7) as u32) << 9)
| (if bos { 1 << 8 } else { 0 })
| (ttl as u32);
Self {
entry: entry.to_be(),
}
}
pub fn label(&self) -> u32 {
(u32::from_be(self.entry) >> 12) & 0xFFFFF
}
pub fn tc(&self) -> u8 {
((u32::from_be(self.entry) >> 9) & 0x7) as u8
}
pub fn is_bos(&self) -> bool {
(u32::from_be(self.entry) & 0x100) != 0
}
pub fn ttl(&self) -> u8 {
(u32::from_be(self.entry) & 0xFF) as u8
}
pub fn as_bytes(&self) -> &[u8] {
<Self as IntoBytes>::as_bytes(self)
}
pub fn from_bytes(data: &[u8]) -> Option<&Self> {
Self::ref_from_prefix(data).map(|(r, _)| r).ok()
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, FromBytes, IntoBytes, Immutable, KnownLayout)]
pub struct RtVia {
pub rtvia_family: u16,
}
impl RtVia {
pub const HEADER_SIZE: usize = std::mem::size_of::<Self>();
pub fn ipv4() -> Self {
Self {
rtvia_family: libc::AF_INET as u16,
}
}
pub fn ipv6() -> Self {
Self {
rtvia_family: libc::AF_INET6 as u16,
}
}
pub fn as_bytes(&self) -> &[u8] {
<Self as IntoBytes>::as_bytes(self)
}
}
pub mod mpls_tunnel {
pub const UNSPEC: u16 = 0;
pub const DST: u16 = 1;
pub const TTL: u16 = 2;
}
pub mod lwtunnel_encap {
pub const NONE: u16 = 0;
pub const MPLS: u16 = 1;
pub const IP: u16 = 2;
pub const ILA: u16 = 3;
pub const IP6: u16 = 4;
pub const SEG6: u16 = 5;
pub const BPF: u16 = 6;
pub const SEG6_LOCAL: u16 = 7;
pub const RPL: u16 = 8;
pub const IOAM6: u16 = 9;
pub const XFRM: u16 = 10;
}
pub mod mpls_label {
pub const IPV4_EXPLICIT_NULL: u32 = 0;
pub const ROUTER_ALERT: u32 = 1;
pub const IPV6_EXPLICIT_NULL: u32 = 2;
pub const IMPLICIT_NULL: u32 = 3;
pub const ENTROPY_INDICATOR: u32 = 7;
pub const GAL: u32 = 13;
pub const OAM_ALERT: u32 = 14;
pub const EXTENSION: u32 = 15;
pub const MAX: u32 = 0xFFFFF; }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mpls_label_entry_size() {
assert_eq!(MplsLabelEntry::SIZE, 4);
}
#[test]
fn test_mpls_label_entry_new() {
let entry = MplsLabelEntry::new(100);
assert_eq!(entry.label(), 100);
assert_eq!(entry.tc(), 0);
assert!(!entry.is_bos());
assert_eq!(entry.ttl(), 0);
}
#[test]
fn test_mpls_label_entry_bottom() {
let entry = MplsLabelEntry::bottom(200, 64);
assert_eq!(entry.label(), 200);
assert_eq!(entry.tc(), 0);
assert!(entry.is_bos());
assert_eq!(entry.ttl(), 64);
}
#[test]
fn test_mpls_label_entry_with_fields() {
let entry = MplsLabelEntry::with_fields(300, 5, true, 128);
assert_eq!(entry.label(), 300);
assert_eq!(entry.tc(), 5);
assert!(entry.is_bos());
assert_eq!(entry.ttl(), 128);
}
#[test]
fn test_mpls_label_entry_max_label() {
let entry = MplsLabelEntry::new(mpls_label::MAX);
assert_eq!(entry.label(), mpls_label::MAX);
}
#[test]
fn test_rtvia_size() {
assert_eq!(RtVia::HEADER_SIZE, 2);
}
}