summaryrefslogtreecommitdiff
path: root/src/protocol/mpls.rs
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2023-09-08 19:50:57 +0800
committerluwenpeng <[email protected]>2023-09-08 19:50:57 +0800
commit3f92925d9c2f7c9417dea89470d9376d09b717f5 (patch)
tree7274476e1265c15f7bd9e83de902795458445b06 /src/protocol/mpls.rs
parent3c6fc844b5e15ae85e08f8bee18e54c30f33d988 (diff)
[feature] Support MPLS/PW Decode
Diffstat (limited to 'src/protocol/mpls.rs')
-rw-r--r--src/protocol/mpls.rs123
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);
+ }
+}