netlink_packet_route/route/
mpls.rs1use 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#[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)]
81pub struct MplsLabel {
83 pub label: u32,
85 pub traffic_class: u8,
87 pub bottom_of_stack: bool,
89 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}