netlink_packet_route/rtnl/route/nlas/
mod.rs1mod cache_info;
4pub use self::cache_info::*;
5
6mod metrics;
7pub use self::metrics::*;
8
9mod mfc_stats;
10pub use self::mfc_stats::*;
11
12mod mpls_ip_tunnel;
13pub use self::mpls_ip_tunnel::*;
14
15mod next_hops;
16pub use self::next_hops::*;
17
18use anyhow::Context;
19use byteorder::{ByteOrder, NativeEndian};
20
21use crate::constants::*;
22
23use netlink_packet_utils::{
24 nla::{self, DefaultNla, NlaBuffer},
25 parsers::{parse_u16, parse_u32},
26 traits::Parseable,
27 DecodeError,
28};
29
30#[cfg(feature = "rich_nlas")]
31use netlink_packet_utils::traits::Emitable;
32
33#[derive(Debug, PartialEq, Eq, Clone)]
36#[non_exhaustive]
37pub enum Nla {
38 #[cfg(not(feature = "rich_nlas"))]
39 Metrics(Vec<u8>),
40 #[cfg(feature = "rich_nlas")]
41 Metrics(Metrics),
42 #[cfg(not(feature = "rich_nlas"))]
43 MfcStats(Vec<u8>),
44 #[cfg(feature = "rich_nlas")]
45 MfcStats(MfcStats),
46 #[cfg(not(feature = "rich_nlas"))]
47 MultiPath(Vec<u8>),
48 #[cfg(feature = "rich_nlas")]
49 MultiPath(Vec<NextHop>),
51 #[cfg(not(feature = "rich_nlas"))]
52 CacheInfo(Vec<u8>),
53 #[cfg(feature = "rich_nlas")]
54 CacheInfo(CacheInfo),
55 Unspec(Vec<u8>),
56 Destination(Vec<u8>),
57 Source(Vec<u8>),
58 Gateway(Vec<u8>),
59 PrefSource(Vec<u8>),
60 Session(Vec<u8>),
61 MpAlgo(Vec<u8>),
62 Via(Vec<u8>),
63 NewDestination(Vec<u8>),
64 Pref(Vec<u8>),
65 Encap(Vec<u8>),
66 Expires(Vec<u8>),
67 Pad(Vec<u8>),
68 Uid(Vec<u8>),
69 TtlPropagate(Vec<u8>),
70 EncapType(u16),
71 Iif(u32),
72 Oif(u32),
73 Priority(u32),
74 ProtocolInfo(u32),
75 Flow(u32),
76 Table(u32),
77 Mark(u32),
78 Other(DefaultNla),
79}
80
81impl nla::Nla for Nla {
82 #[rustfmt::skip]
83 fn value_len(&self) -> usize {
84 use self::Nla::*;
85 match *self {
86 Unspec(ref bytes)
87 | Destination(ref bytes)
88 | Source(ref bytes)
89 | Gateway(ref bytes)
90 | PrefSource(ref bytes)
91 | Session(ref bytes)
92 | MpAlgo(ref bytes)
93 | Via(ref bytes)
94 | NewDestination(ref bytes)
95 | Pref(ref bytes)
96 | Encap(ref bytes)
97 | Expires(ref bytes)
98 | Pad(ref bytes)
99 | Uid(ref bytes)
100 | TtlPropagate(ref bytes)
101 => bytes.len(),
102
103 #[cfg(not(feature = "rich_nlas"))]
104 CacheInfo(ref bytes)
105 | MfcStats(ref bytes)
106 | Metrics(ref bytes)
107 | MultiPath(ref bytes)
108 => bytes.len(),
109
110 #[cfg(feature = "rich_nlas")]
111 CacheInfo(ref cache_info) => cache_info.buffer_len(),
112 #[cfg(feature = "rich_nlas")]
113 MfcStats(ref stats) => stats.buffer_len(),
114 #[cfg(feature = "rich_nlas")]
115 Metrics(ref metrics) => metrics.buffer_len(),
116 #[cfg(feature = "rich_nlas")]
117 MultiPath(ref next_hops) => next_hops.iter().map(|nh| nh.buffer_len()).sum(),
118
119 EncapType(_) => 2,
120 Iif(_)
121 | Oif(_)
122 | Priority(_)
123 | ProtocolInfo(_)
124 | Flow(_)
125 | Table(_)
126 | Mark(_)
127 => 4,
128
129 Other(ref attr) => attr.value_len(),
130 }
131 }
132
133 #[rustfmt::skip]
134 fn emit_value(&self, buffer: &mut [u8]) {
135 use self::Nla::*;
136 match *self {
137 Unspec(ref bytes)
138 | Destination(ref bytes)
139 | Source(ref bytes)
140 | Gateway(ref bytes)
141 | PrefSource(ref bytes)
142 | Session(ref bytes)
143 | MpAlgo(ref bytes)
144 | Via(ref bytes)
145 | NewDestination(ref bytes)
146 | Pref(ref bytes)
147 | Encap(ref bytes)
148 | Expires(ref bytes)
149 | Pad(ref bytes)
150 | Uid(ref bytes)
151 | TtlPropagate(ref bytes)
152 => buffer.copy_from_slice(bytes.as_slice()),
153
154 #[cfg(not(feature = "rich_nlas"))]
155 MultiPath(ref bytes)
156 | CacheInfo(ref bytes)
157 | MfcStats(ref bytes)
158 | Metrics(ref bytes)
159 => buffer.copy_from_slice(bytes.as_slice()),
160
161 #[cfg(feature = "rich_nlas")]
162 CacheInfo(ref cache_info) => cache_info.emit(buffer),
163 #[cfg(feature = "rich_nlas")]
164 MfcStats(ref stats) => stats.emit(buffer),
165 #[cfg(feature = "rich_nlas")]
166 Metrics(ref metrics) => metrics.emit(buffer),
167 #[cfg(feature = "rich_nlas")]
168 MultiPath(ref next_hops) => {
169 let mut offset = 0;
170 for nh in next_hops {
171 let len = nh.buffer_len();
172 nh.emit(&mut buffer[offset..offset+len]);
173 offset += len
174 }
175 }
176
177 EncapType(value) => NativeEndian::write_u16(buffer, value),
178 Iif(value)
179 | Oif(value)
180 | Priority(value)
181 | ProtocolInfo(value)
182 | Flow(value)
183 | Table(value)
184 | Mark(value)
185 => NativeEndian::write_u32(buffer, value),
186 Other(ref attr) => attr.emit_value(buffer),
187 }
188 }
189
190 fn kind(&self) -> u16 {
191 use self::Nla::*;
192 match *self {
193 Unspec(_) => RTA_UNSPEC,
194 Destination(_) => RTA_DST,
195 Source(_) => RTA_SRC,
196 Iif(_) => RTA_IIF,
197 Oif(_) => RTA_OIF,
198 Gateway(_) => RTA_GATEWAY,
199 Priority(_) => RTA_PRIORITY,
200 PrefSource(_) => RTA_PREFSRC,
201 Metrics(_) => RTA_METRICS,
202 MultiPath(_) => RTA_MULTIPATH,
203 ProtocolInfo(_) => RTA_PROTOINFO,
204 Flow(_) => RTA_FLOW,
205 CacheInfo(_) => RTA_CACHEINFO,
206 Session(_) => RTA_SESSION,
207 MpAlgo(_) => RTA_MP_ALGO,
208 Table(_) => RTA_TABLE,
209 Mark(_) => RTA_MARK,
210 MfcStats(_) => RTA_MFC_STATS,
211 Via(_) => RTA_VIA,
212 NewDestination(_) => RTA_NEWDST,
213 Pref(_) => RTA_PREF,
214 EncapType(_) => RTA_ENCAP_TYPE,
215 Encap(_) => RTA_ENCAP,
216 Expires(_) => RTA_EXPIRES,
217 Pad(_) => RTA_PAD,
218 Uid(_) => RTA_UID,
219 TtlPropagate(_) => RTA_TTL_PROPAGATE,
220 Other(ref attr) => attr.kind(),
221 }
222 }
223}
224
225impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
226 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
227 use self::Nla::*;
228
229 let payload = buf.value();
230 Ok(match buf.kind() {
231 RTA_UNSPEC => Unspec(payload.to_vec()),
232 RTA_DST => Destination(payload.to_vec()),
233 RTA_SRC => Source(payload.to_vec()),
234 RTA_GATEWAY => Gateway(payload.to_vec()),
235 RTA_PREFSRC => PrefSource(payload.to_vec()),
236 RTA_SESSION => Session(payload.to_vec()),
237 RTA_MP_ALGO => MpAlgo(payload.to_vec()),
238 RTA_VIA => Via(payload.to_vec()),
239 RTA_NEWDST => NewDestination(payload.to_vec()),
240 RTA_PREF => Pref(payload.to_vec()),
241 RTA_ENCAP => Encap(payload.to_vec()),
242 RTA_EXPIRES => Expires(payload.to_vec()),
243 RTA_PAD => Pad(payload.to_vec()),
244 RTA_UID => Uid(payload.to_vec()),
245 RTA_TTL_PROPAGATE => TtlPropagate(payload.to_vec()),
246 RTA_ENCAP_TYPE => EncapType(
247 parse_u16(payload).context("invalid RTA_ENCAP_TYPE value")?,
248 ),
249 RTA_IIF => {
250 Iif(parse_u32(payload).context("invalid RTA_IIF value")?)
251 }
252 RTA_OIF => {
253 Oif(parse_u32(payload).context("invalid RTA_OIF value")?)
254 }
255 RTA_PRIORITY => Priority(
256 parse_u32(payload).context("invalid RTA_PRIORITY value")?,
257 ),
258 RTA_PROTOINFO => ProtocolInfo(
259 parse_u32(payload).context("invalid RTA_PROTOINFO value")?,
260 ),
261 RTA_FLOW => {
262 Flow(parse_u32(payload).context("invalid RTA_FLOW value")?)
263 }
264 RTA_TABLE => {
265 Table(parse_u32(payload).context("invalid RTA_TABLE value")?)
266 }
267 RTA_MARK => {
268 Mark(parse_u32(payload).context("invalid RTA_MARK value")?)
269 }
270
271 #[cfg(not(feature = "rich_nlas"))]
272 RTA_CACHEINFO => CacheInfo(payload.to_vec()),
273 #[cfg(feature = "rich_nlas")]
274 RTA_CACHEINFO => CacheInfo(
275 cache_info::CacheInfo::parse(
276 &CacheInfoBuffer::new_checked(payload)
277 .context("invalid RTA_CACHEINFO value")?,
278 )
279 .context("invalid RTA_CACHEINFO value")?,
280 ),
281 #[cfg(not(feature = "rich_nlas"))]
282 RTA_MFC_STATS => MfcStats(payload.to_vec()),
283 #[cfg(feature = "rich_nlas")]
284 RTA_MFC_STATS => MfcStats(
285 mfc_stats::MfcStats::parse(
286 &MfcStatsBuffer::new_checked(payload)
287 .context("invalid RTA_MFC_STATS value")?,
288 )
289 .context("invalid RTA_MFC_STATS value")?,
290 ),
291 #[cfg(not(feature = "rich_nlas"))]
292 RTA_METRICS => Metrics(payload.to_vec()),
293 #[cfg(feature = "rich_nlas")]
294 RTA_METRICS => Metrics(
295 metrics::Metrics::parse(
296 &NlaBuffer::new_checked(payload)
297 .context("invalid RTA_METRICS value")?,
298 )
299 .context("invalid RTA_METRICS value")?,
300 ),
301 #[cfg(not(feature = "rich_nlas"))]
302 RTA_MULTIPATH => MultiPath(payload.to_vec()),
303 #[cfg(feature = "rich_nlas")]
304 RTA_MULTIPATH => {
305 let mut next_hops = vec![];
306 let mut buf = payload;
307 loop {
308 let nh_buf = NextHopBuffer::new_checked(&buf)
309 .context("invalid RTA_MULTIPATH value")?;
310 let len = nh_buf.length() as usize;
311 let nh = NextHop::parse(&nh_buf)
312 .context("invalid RTA_MULTIPATH value")?;
313 next_hops.push(nh);
314 if buf.len() == len {
315 break;
316 }
317 buf = &buf[len..];
318 }
319 MultiPath(next_hops)
320 }
321 _ => Other(
322 DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
323 ),
324 })
325 }
326}