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