use std::fmt::{self, Formatter};
use zerocopy::byteorder::{BigEndian, U32};
use zerocopy::{FromBytes, IntoBytes, Unaligned};
use crate::packet::{HeaderParser, PacketHeader};
pub const MPLS_ETHERTYPE_UNICAST: u16 = 0x8847;
pub const MPLS_ETHERTYPE_MULTICAST: u16 = 0x8848;
#[inline]
pub fn is_mpls_ethertype(ethertype: u16) -> bool {
ethertype == MPLS_ETHERTYPE_UNICAST || ethertype == MPLS_ETHERTYPE_MULTICAST
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum MplsReservedLabel {
Ipv4ExplicitNull = 0,
RouterAlert = 1,
Ipv6ExplicitNull = 2,
ImplicitNull = 3,
EntropyLabelIndicator = 7,
Gal = 13,
OamAlert = 14,
Extension = 15,
}
impl MplsReservedLabel {
#[inline]
pub fn is_reserved(label: u32) -> bool {
label <= 15
}
pub fn from_label(label: u32) -> Option<Self> {
match label {
0 => Some(MplsReservedLabel::Ipv4ExplicitNull),
1 => Some(MplsReservedLabel::RouterAlert),
2 => Some(MplsReservedLabel::Ipv6ExplicitNull),
3 => Some(MplsReservedLabel::ImplicitNull),
7 => Some(MplsReservedLabel::EntropyLabelIndicator),
13 => Some(MplsReservedLabel::Gal),
14 => Some(MplsReservedLabel::OamAlert),
15 => Some(MplsReservedLabel::Extension),
_ => None,
}
}
}
impl fmt::Display for MplsReservedLabel {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
MplsReservedLabel::Ipv4ExplicitNull => write!(f, "IPv4 Explicit NULL"),
MplsReservedLabel::RouterAlert => write!(f, "Router Alert"),
MplsReservedLabel::Ipv6ExplicitNull => write!(f, "IPv6 Explicit NULL"),
MplsReservedLabel::ImplicitNull => write!(f, "Implicit NULL"),
MplsReservedLabel::EntropyLabelIndicator => write!(f, "Entropy Label Indicator"),
MplsReservedLabel::Gal => write!(f, "GAL"),
MplsReservedLabel::OamAlert => write!(f, "OAM Alert"),
MplsReservedLabel::Extension => write!(f, "Extension"),
}
}
}
#[repr(C, packed)]
#[derive(
FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
)]
pub struct MplsLabel {
label_tc_s_ttl: U32<BigEndian>,
}
impl MplsLabel {
pub const LABEL_MASK: u32 = 0xFFFFF000;
pub const LABEL_SHIFT: u32 = 12;
pub const TC_MASK: u32 = 0x00000E00;
pub const TC_SHIFT: u32 = 9;
pub const BOS_MASK: u32 = 0x00000100;
pub const BOS_SHIFT: u32 = 8;
pub const TTL_MASK: u32 = 0x000000FF;
pub const MAX_LABEL: u32 = 0xFFFFF;
pub const MAX_TC: u8 = 7;
#[allow(unused)]
const NAME: &'static str = "MplsLabel";
#[inline]
pub fn raw(&self) -> u32 {
self.label_tc_s_ttl.get()
}
#[inline]
pub fn label(&self) -> u32 {
(self.raw() & Self::LABEL_MASK) >> Self::LABEL_SHIFT
}
#[inline]
pub fn traffic_class(&self) -> u8 {
((self.raw() & Self::TC_MASK) >> Self::TC_SHIFT) as u8
}
#[inline]
pub fn exp(&self) -> u8 {
self.traffic_class()
}
#[inline]
pub fn is_bottom_of_stack(&self) -> bool {
self.raw() & Self::BOS_MASK != 0
}
#[inline]
pub fn ttl(&self) -> u8 {
(self.raw() & Self::TTL_MASK) as u8
}
#[inline]
pub fn is_reserved(&self) -> bool {
MplsReservedLabel::is_reserved(self.label())
}
#[inline]
pub fn reserved_label(&self) -> Option<MplsReservedLabel> {
MplsReservedLabel::from_label(self.label())
}
#[inline]
pub fn is_ipv4_explicit_null(&self) -> bool {
self.label() == 0
}
#[inline]
pub fn is_ipv6_explicit_null(&self) -> bool {
self.label() == 2
}
#[inline]
pub fn is_implicit_null(&self) -> bool {
self.label() == 3
}
#[inline]
pub fn is_router_alert(&self) -> bool {
self.label() == 1
}
#[inline]
fn is_valid(&self) -> bool {
true
}
}
impl PacketHeader for MplsLabel {
const NAME: &'static str = "MplsLabel";
type InnerType = u32;
#[inline]
fn inner_type(&self) -> Self::InnerType {
self.label()
}
#[inline]
fn total_len(&self, _buf: &[u8]) -> usize {
Self::FIXED_LEN }
#[inline]
fn is_valid(&self) -> bool {
self.is_valid()
}
}
impl HeaderParser for MplsLabel {
type Output<'a> = &'a MplsLabel;
#[inline]
fn into_view<'a>(header: &'a Self, _options: &'a [u8]) -> Self::Output<'a> {
header
}
}
impl fmt::Display for MplsLabel {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"MPLS label={} tc={} s={} ttl={}",
self.label(),
self.traffic_class(),
if self.is_bottom_of_stack() { 1 } else { 0 },
self.ttl()
)?;
if let Some(reserved) = self.reserved_label() {
write!(f, " ({})", reserved)?;
}
Ok(())
}
}
pub struct MplsLabelStackIter<'a> {
data: &'a [u8],
finished: bool,
}
impl<'a> MplsLabelStackIter<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
finished: false,
}
}
pub fn remaining(&self) -> &'a [u8] {
self.data
}
pub fn skip_to_payload(mut self) -> &'a [u8] {
while self.next().is_some() {}
self.data
}
pub fn collect_labels(self) -> Vec<MplsLabel> {
self.copied().collect()
}
}
impl<'a> Iterator for MplsLabelStackIter<'a> {
type Item = &'a MplsLabel;
fn next(&mut self) -> Option<Self::Item> {
if self.finished || self.data.len() < 4 {
return None;
}
let (label_ref, rest) = zerocopy::Ref::<_, MplsLabel>::from_prefix(self.data).ok()?;
let label = zerocopy::Ref::into_ref(label_ref);
if label.is_bottom_of_stack() {
self.finished = true;
}
self.data = rest;
Some(label)
}
}
#[derive(Debug, Clone)]
pub struct MplsLabelStack<'a> {
pub data: &'a [u8],
pub count: usize,
pub total_size: usize,
}
impl<'a> MplsLabelStack<'a> {
pub fn parse(data: &'a [u8]) -> Option<(Self, &'a [u8])> {
let mut offset = 0;
let mut count = 0;
loop {
if data.len() < offset + 4 {
return None; }
let label_data = &data[offset..offset + 4];
let raw =
u32::from_be_bytes([label_data[0], label_data[1], label_data[2], label_data[3]]);
count += 1;
offset += 4;
if raw & MplsLabel::BOS_MASK != 0 {
break;
}
if count > 16 {
return None;
}
}
Some((
MplsLabelStack {
data: &data[..offset],
count,
total_size: offset,
},
&data[offset..],
))
}
pub fn iter(&self) -> MplsLabelStackIter<'a> {
MplsLabelStackIter::new(self.data)
}
pub fn first(&self) -> Option<&'a MplsLabel> {
self.iter().next()
}
pub fn last(&self) -> Option<&'a MplsLabel> {
self.iter().last()
}
}
impl<'a> IntoIterator for &'a MplsLabelStack<'a> {
type Item = &'a MplsLabel;
type IntoIter = MplsLabelStackIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl fmt::Display for MplsLabelStack<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "MPLS[")?;
let mut first = true;
for label in self.iter() {
if !first {
write!(f, " -> ")?;
}
write!(f, "{}", label.label())?;
first = false;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mpls_label_size() {
assert_eq!(std::mem::size_of::<MplsLabel>(), 4);
assert_eq!(MplsLabel::FIXED_LEN, 4);
}
#[test]
fn test_mpls_single_label() {
let packet = vec![0x00, 0x01, 0x01, 0x40, 0x45, 0x00, 0x00, 0x00];
let (label, payload) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 16);
assert_eq!(label.traffic_class(), 0);
assert!(label.is_bottom_of_stack());
assert_eq!(label.ttl(), 64);
assert_eq!(payload.len(), 4);
}
#[test]
fn test_mpls_label_max_value() {
let packet = vec![0xFF, 0xFF, 0xFF, 0xFF];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 0xFFFFF);
assert_eq!(label.traffic_class(), 7);
assert!(label.is_bottom_of_stack());
assert_eq!(label.ttl(), 255);
}
#[test]
fn test_mpls_label_zero() {
let packet = vec![0x00, 0x00, 0x01, 0x01];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 0);
assert!(label.is_ipv4_explicit_null());
assert!(label.is_reserved());
assert_eq!(
label.reserved_label(),
Some(MplsReservedLabel::Ipv4ExplicitNull)
);
}
#[test]
fn test_mpls_label_ipv6_explicit_null() {
let packet = vec![0x00, 0x00, 0x21, 0x40];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 2);
assert!(label.is_ipv6_explicit_null());
assert!(label.is_reserved());
}
#[test]
fn test_mpls_label_router_alert() {
let packet = vec![0x00, 0x00, 0x11, 0x40];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 1);
assert!(label.is_router_alert());
}
#[test]
fn test_mpls_label_implicit_null() {
let packet = vec![0x00, 0x00, 0x31, 0x40];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 3);
assert!(label.is_implicit_null());
}
#[test]
fn test_mpls_label_not_bos() {
let packet = vec![0x00, 0x06, 0x46, 0x80];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.label(), 100);
assert_eq!(label.traffic_class(), 3);
assert!(!label.is_bottom_of_stack());
assert_eq!(label.ttl(), 128);
}
#[test]
fn test_mpls_label_stack_iterator() {
let packet = vec![
0x00, 0x01, 0x00, 0x40, 0x00, 0x02, 0x01, 0x3F, 0x45, 0x00, 0x00, 0x00, ];
let mut iter = MplsLabelStackIter::new(&packet);
let first = iter.next().unwrap();
assert_eq!(first.label(), 16);
assert!(!first.is_bottom_of_stack());
let second = iter.next().unwrap();
assert_eq!(second.label(), 32);
assert!(second.is_bottom_of_stack());
assert!(iter.next().is_none());
assert_eq!(iter.remaining().len(), 4);
}
#[test]
fn test_mpls_label_stack_three_labels() {
let packet = vec![
0x00, 0x00, 0xC0, 0x40, 0x00, 0x01, 0x80, 0x3F, 0x00, 0x02, 0x41, 0x3E, 0x45, 0x00, ];
let mut iter = MplsLabelStackIter::new(&packet);
let first = iter.next().unwrap();
assert_eq!(first.label(), 12);
assert!(!first.is_bottom_of_stack());
let second = iter.next().unwrap();
assert_eq!(second.label(), 24);
assert!(!second.is_bottom_of_stack());
let third = iter.next().unwrap();
assert_eq!(third.label(), 36);
assert!(third.is_bottom_of_stack());
assert!(iter.next().is_none());
}
#[test]
fn test_mpls_label_stack_skip_to_payload() {
let packet = vec![
0x00, 0x01, 0x00, 0x40, 0x00, 0x02, 0x01, 0x3F, 0x45, 0x00, 0x00, 0x14, ];
let iter = MplsLabelStackIter::new(&packet);
let payload = iter.skip_to_payload();
assert_eq!(payload.len(), 4);
assert_eq!(payload[0], 0x45); }
#[test]
fn test_mpls_label_stack_collect() {
let packet = vec![
0x00, 0x01, 0x00, 0x40, 0x00, 0x02, 0x01, 0x3F, ];
let iter = MplsLabelStackIter::new(&packet);
let labels: Vec<MplsLabel> = iter.collect_labels();
assert_eq!(labels.len(), 2);
assert_eq!(labels[0].label(), 16);
assert_eq!(labels[1].label(), 32);
}
#[test]
fn test_mpls_label_stack_parse() {
let packet = vec![
0x00, 0x01, 0x00, 0x40, 0x00, 0x02, 0x01, 0x3F, 0x45, 0x00, 0x00, 0x14,
];
let (stack, payload) = MplsLabelStack::parse(&packet).unwrap();
assert_eq!(stack.count, 2);
assert_eq!(stack.total_size, 8);
assert_eq!(payload.len(), 4);
let first = stack.first().unwrap();
assert_eq!(first.label(), 16);
let last = stack.last().unwrap();
assert_eq!(last.label(), 32);
}
#[test]
fn test_mpls_label_stack_single() {
let packet = vec![
0x00, 0x01, 0x01, 0x40, 0x45, 0x00,
];
let (stack, payload) = MplsLabelStack::parse(&packet).unwrap();
assert_eq!(stack.count, 1);
assert_eq!(stack.total_size, 4);
assert_eq!(payload.len(), 2);
}
#[test]
fn test_mpls_label_too_small() {
let packet = vec![0x00, 0x01, 0x01]; let result = MplsLabel::from_bytes(&packet);
assert!(result.is_err());
}
#[test]
fn test_mpls_label_stack_empty() {
let packet: Vec<u8> = vec![];
let result = MplsLabelStack::parse(&packet);
assert!(result.is_none());
}
#[test]
fn test_mpls_display() {
let packet = vec![0x00, 0x01, 0x01, 0x40];
let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
let display = format!("{}", label);
assert!(display.contains("label=16"));
assert!(display.contains("ttl=64"));
}
#[test]
fn test_mpls_display_reserved() {
let packet = vec![0x00, 0x00, 0x01, 0x40]; let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
let display = format!("{}", label);
assert!(display.contains("IPv4 Explicit NULL"));
}
#[test]
fn test_mpls_label_stack_display() {
let packet = vec![
0x00, 0x01, 0x00, 0x40, 0x00, 0x02, 0x01, 0x3F, ];
let (stack, _) = MplsLabelStack::parse(&packet).unwrap();
let display = format!("{}", stack);
assert!(display.contains("MPLS["));
assert!(display.contains("16"));
assert!(display.contains("32"));
}
#[test]
fn test_mpls_reserved_labels() {
assert!(MplsReservedLabel::is_reserved(0));
assert!(MplsReservedLabel::is_reserved(15));
assert!(!MplsReservedLabel::is_reserved(16));
assert_eq!(
MplsReservedLabel::from_label(0),
Some(MplsReservedLabel::Ipv4ExplicitNull)
);
assert_eq!(
MplsReservedLabel::from_label(1),
Some(MplsReservedLabel::RouterAlert)
);
assert_eq!(
MplsReservedLabel::from_label(13),
Some(MplsReservedLabel::Gal)
);
assert_eq!(MplsReservedLabel::from_label(16), None);
}
#[test]
fn test_mpls_exp_alias() {
let packet = vec![0x00, 0x06, 0x47, 0x40]; let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.exp(), label.traffic_class());
assert_eq!(label.exp(), 3);
}
#[test]
fn test_mpls_ethertype() {
assert!(is_mpls_ethertype(0x8847));
assert!(is_mpls_ethertype(0x8848));
assert!(!is_mpls_ethertype(0x0800));
}
#[test]
fn test_mpls_inner_type() {
let packet = vec![0x00, 0x10, 0x01, 0x40]; let (label, _) = MplsLabel::from_bytes(&packet).unwrap();
assert_eq!(label.inner_type(), 256);
}
#[test]
fn test_mpls_label_into_iter() {
let packet = vec![0x00, 0x01, 0x00, 0x40, 0x00, 0x02, 0x01, 0x3F];
let (stack, _) = MplsLabelStack::parse(&packet).unwrap();
let labels: Vec<u32> = (&stack).into_iter().map(|l| l.label()).collect();
assert_eq!(labels, vec![16, 32]);
}
}