netlink_packet_route/route/
mpls.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    parse_u8, DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
5    Parseable,
6};
7
8const MPLS_IPTUNNEL_DST: u16 = 1;
9const MPLS_IPTUNNEL_TTL: u16 = 2;
10
11/// Netlink attributes for `RTA_ENCAP` with `RTA_ENCAP_TYPE` set to
12/// `LWTUNNEL_ENCAP_MPLS`.
13#[derive(Debug, PartialEq, Eq, Clone)]
14#[non_exhaustive]
15pub enum RouteMplsIpTunnel {
16    Destination(Vec<MplsLabel>),
17    Ttl(u8),
18    Other(DefaultNla),
19}
20
21impl Nla for RouteMplsIpTunnel {
22    fn value_len(&self) -> usize {
23        match self {
24            Self::Destination(v) => VecMplsLabel(v.to_vec()).buffer_len(),
25            Self::Ttl(_) => 1,
26            Self::Other(attr) => attr.value_len(),
27        }
28    }
29
30    fn kind(&self) -> u16 {
31        match self {
32            Self::Destination(_) => MPLS_IPTUNNEL_DST,
33            Self::Ttl(_) => MPLS_IPTUNNEL_TTL,
34            Self::Other(attr) => attr.kind(),
35        }
36    }
37
38    fn emit_value(&self, buffer: &mut [u8]) {
39        match self {
40            Self::Destination(v) => VecMplsLabel(v.to_vec()).emit(buffer),
41            Self::Ttl(ttl) => buffer[0] = *ttl,
42            Self::Other(attr) => attr.emit_value(buffer),
43        }
44    }
45}
46
47impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
48    for RouteMplsIpTunnel
49{
50    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
51        let payload = buf.value();
52        Ok(match buf.kind() {
53            MPLS_IPTUNNEL_DST => Self::Destination(
54                VecMplsLabel::parse(payload)
55                    .context(format!(
56                        "invalid MPLS_IPTUNNEL_DST value {payload:?}"
57                    ))?
58                    .0,
59            ),
60            MPLS_IPTUNNEL_TTL => Self::Ttl(
61                parse_u8(payload).context("invalid MPLS_IPTUNNEL_TTL value")?,
62            ),
63            _ => Self::Other(
64                DefaultNla::parse(buf)
65                    .context("invalid NLA value (unknown type) value")?,
66            ),
67        })
68    }
69}
70
71const MPLS_LS_LABEL_MASK: u32 = 0xFFFFF000;
72const MPLS_LS_LABEL_SHIFT: u32 = 12;
73const MPLS_LS_TC_MASK: u32 = 0x00000E00;
74const MPLS_LS_TC_SHIFT: u32 = 9;
75const MPLS_LS_S_MASK: u32 = 0x00000100;
76const MPLS_LS_S_SHIFT: u32 = 8;
77const MPLS_LS_TTL_MASK: u32 = 0x000000FF;
78const MPLS_LS_TTL_SHIFT: u32 = 0;
79
80#[derive(Debug, PartialEq, Eq, Clone, Copy)]
81/// MPLS label defined in RFC 3032 and updated by RFC 5462
82pub struct MplsLabel {
83    /// label, 20 bytes
84    pub label: u32,
85    /// Traffic Class, 3 bits
86    pub traffic_class: u8,
87    /// Bottom of Stack, 1 bit
88    pub bottom_of_stack: bool,
89    /// Time to Live
90    pub ttl: u8,
91}
92
93impl MplsLabel {
94    pub(crate) fn parse(payload: &[u8]) -> Result<Self, DecodeError> {
95        if payload.len() == 4 {
96            Ok(Self::from(u32::from_be_bytes([
97                payload[0], payload[1], payload[2], payload[3],
98            ])))
99        } else {
100            Err(DecodeError::from(format!(
101                "Invalid u8 array length {}, expecting 4 bytes for MPLS \
102                 label, got {:?}",
103                payload.len(),
104                payload,
105            )))
106        }
107    }
108}
109
110impl Emitable for MplsLabel {
111    fn buffer_len(&self) -> usize {
112        4
113    }
114
115    fn emit(&self, buffer: &mut [u8]) {
116        buffer.copy_from_slice(u32::from(*self).to_be_bytes().as_slice())
117    }
118}
119
120impl From<u32> for MplsLabel {
121    fn from(d: u32) -> Self {
122        let label = (d & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
123        let traffic_class = ((d & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT) as u8;
124        let bottom_of_stack = (d & MPLS_LS_S_MASK) > 0;
125        let ttl = (d & MPLS_LS_TTL_MASK) as u8;
126        Self {
127            label,
128            traffic_class,
129            bottom_of_stack,
130            ttl,
131        }
132    }
133}
134
135impl From<MplsLabel> for u32 {
136    fn from(v: MplsLabel) -> u32 {
137        (v.label << MPLS_LS_LABEL_SHIFT)
138            | ((v.traffic_class as u32) << MPLS_LS_TC_SHIFT)
139            | ((v.bottom_of_stack as u32) << MPLS_LS_S_SHIFT)
140            | ((v.ttl as u32) << MPLS_LS_TTL_SHIFT)
141    }
142}
143
144pub(crate) struct VecMplsLabel(pub(crate) Vec<MplsLabel>);
145
146impl VecMplsLabel {
147    pub(crate) fn parse(payload: &[u8]) -> Result<Self, DecodeError> {
148        let mut labels = vec![];
149        let mut i: usize = 0;
150        while i + 4 <= payload.len() {
151            labels.push(MplsLabel::parse(&payload[i..i + 4])?);
152            i += 4;
153        }
154        Ok(Self(labels))
155    }
156}
157
158impl Emitable for VecMplsLabel {
159    fn buffer_len(&self) -> usize {
160        self.0.len() * 4
161    }
162
163    fn emit(&self, buffer: &mut [u8]) {
164        for (i, label) in self.0.iter().enumerate() {
165            label.emit(&mut buffer[i * 4..i * 4 + 4]);
166        }
167    }
168}
169
170const MPLS_TTL_PROP_DEFAULT: u8 = 0;
171const MPLS_TTL_PROP_ENABLED: u8 = 1;
172const MPLS_TTL_PROP_DISABLED: u8 = 2;
173
174#[derive(Debug, PartialEq, Eq, Clone, Default, Copy)]
175#[non_exhaustive]
176pub enum RouteMplsTtlPropagation {
177    #[default]
178    Default,
179    Enabled,
180    Disabled,
181    Other(u8),
182}
183
184impl From<u8> for RouteMplsTtlPropagation {
185    fn from(d: u8) -> Self {
186        match d {
187            MPLS_TTL_PROP_DEFAULT => Self::Default,
188            MPLS_TTL_PROP_ENABLED => Self::Enabled,
189            MPLS_TTL_PROP_DISABLED => Self::Disabled,
190            _ => Self::Other(d),
191        }
192    }
193}
194
195impl From<RouteMplsTtlPropagation> for u8 {
196    fn from(v: RouteMplsTtlPropagation) -> u8 {
197        match v {
198            RouteMplsTtlPropagation::Default => MPLS_TTL_PROP_DEFAULT,
199            RouteMplsTtlPropagation::Enabled => MPLS_TTL_PROP_ENABLED,
200            RouteMplsTtlPropagation::Disabled => MPLS_TTL_PROP_DISABLED,
201            RouteMplsTtlPropagation::Other(d) => d,
202        }
203    }
204}