diff options
| author | luwenpeng <[email protected]> | 2023-09-08 19:50:57 +0800 |
|---|---|---|
| committer | luwenpeng <[email protected]> | 2023-09-08 19:50:57 +0800 |
| commit | 3f92925d9c2f7c9417dea89470d9376d09b717f5 (patch) | |
| tree | 7274476e1265c15f7bd9e83de902795458445b06 /src/protocol/mpls.rs | |
| parent | 3c6fc844b5e15ae85e08f8bee18e54c30f33d988 (diff) | |
[feature] Support MPLS/PW Decode
Diffstat (limited to 'src/protocol/mpls.rs')
| -rw-r--r-- | src/protocol/mpls.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/protocol/mpls.rs b/src/protocol/mpls.rs new file mode 100644 index 0000000..2c4c443 --- /dev/null +++ b/src/protocol/mpls.rs @@ -0,0 +1,123 @@ +use crate::protocol::codec::Decode; +use nom::bits; +use nom::error::Error; +use nom::number; +use nom::sequence; +use nom::IResult; + +/****************************************************************************** + * Struct + ******************************************************************************/ + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct MplsHeader { + pub label: u32, + pub experimental: u8, + pub bottom_of_stack: bool, + pub ttl: u8, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +// Ethernet pseudowire (PW) https://tools.ietf.org/html/rfc4448#section-3.1 +pub struct PwEthHeader { + pub control_word: u32, +} + +/****************************************************************************** + * API + ******************************************************************************/ + +fn bit_decode(input: &[u8]) -> IResult<&[u8], (u32, u8, u8, u8)> { + bits::bits::<_, _, Error<_>, _, _>(sequence::tuple(( + bits::streaming::take(20u8), + bits::streaming::take(3u8), + bits::streaming::take(1u8), + bits::streaming::take(8u8), + )))(input) +} + +impl Decode for MplsHeader { + type Iterm = MplsHeader; + fn decode(input: &[u8]) -> IResult<&[u8], MplsHeader> { + let (input, (label, experimental, bottom_of_stack, ttl)) = bit_decode(input)?; + + Ok(( + input, + MplsHeader { + label, + experimental, + bottom_of_stack: bottom_of_stack == 1, + ttl, + }, + )) + } +} + +impl Decode for PwEthHeader { + type Iterm = PwEthHeader; + fn decode(input: &[u8]) -> IResult<&[u8], PwEthHeader> { + let (input, control_word) = number::streaming::be_u32(input)?; + + Ok((input, PwEthHeader { control_word })) + } +} + +/****************************************************************************** + * TEST + ******************************************************************************/ + +#[cfg(test)] +mod tests { + use super::MplsHeader; + use crate::protocol::codec::Decode; + const LAST_SLICE: &'static [u8] = &[0xff]; + + #[test] + fn mpls_header_decode() { + /* + * MultiProtocol Label Switching Header, Label: 18, Exp: 5, S: 0, TTL: 255 + * 0000 0000 0000 0001 0010 .... .... .... = MPLS Label: 18 (0x00012) + * .... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5 + * .... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0 + * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255 + * MultiProtocol Label Switching Header, Label: 16, Exp: 5, S: 1, TTL: 255 + * 0000 0000 0000 0001 0000 .... .... .... = MPLS Label: 16 (0x00010) + * .... .... .... .... .... 101. .... .... = MPLS Experimental Bits: 5 + * .... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1 + * .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255 + */ + + let bytes = [0x00, 0x01, 0x2a, 0xff, 0x00, 0x01, 0x0b, 0xff, 0xff]; + + let expectation1 = MplsHeader { + label: 18, + experimental: 5, + bottom_of_stack: false, + ttl: 255, + }; + let expectation2 = MplsHeader { + label: 16, + experimental: 5, + bottom_of_stack: true, + ttl: 255, + }; + + assert_eq!(MplsHeader::decode(&bytes), Ok((&bytes[4..], expectation1))); + assert_eq!( + MplsHeader::decode(&bytes[4..]), + Ok((LAST_SLICE, expectation2)) + ); + + // example + let mut payload = &bytes[..]; + while let Ok((remain, header)) = MplsHeader::decode(payload) { + println!("return: {:?}, payload: {}", header, remain.len()); + payload = remain; + if header.bottom_of_stack { + break; + } + } + + // assert_eq!(1, 0); + } +} |
