1use netlink_packet_core::{
4 emit_u32, emit_u64, parse_u16, parse_u32, parse_u64, parse_u8, DecodeError,
5 DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer, Parseable,
6 ParseableParametrized,
7};
8
9use super::{
10 super::AddressFamily, lwtunnel::VecRouteLwTunnelEncap,
11 metrics::VecRouteMetric, mpls::VecMplsLabel, MplsLabel, RouteAddress,
12 RouteCacheInfo, RouteCacheInfoBuffer, RouteLwEnCapType, RouteLwTunnelEncap,
13 RouteMetric, RouteMfcStats, RouteMfcStatsBuffer, RouteMplsTtlPropagation,
14 RouteNextHop, RouteNextHopBuffer, RoutePreference, RouteRealm, RouteType,
15 RouteVia, RouteViaBuffer,
16};
17
18const RTA_DST: u16 = 1;
19const RTA_SRC: u16 = 2;
20const RTA_IIF: u16 = 3;
21const RTA_OIF: u16 = 4;
22const RTA_GATEWAY: u16 = 5;
23const RTA_PRIORITY: u16 = 6;
24const RTA_PREFSRC: u16 = 7;
25const RTA_METRICS: u16 = 8;
26const RTA_MULTIPATH: u16 = 9;
27const RTA_FLOW: u16 = 11;
29const RTA_CACHEINFO: u16 = 12;
30const RTA_TABLE: u16 = 15;
33const RTA_MARK: u16 = 16;
34const RTA_MFC_STATS: u16 = 17;
35const RTA_VIA: u16 = 18;
36const RTA_NEWDST: u16 = 19;
37const RTA_PREF: u16 = 20;
38pub(crate) const RTA_ENCAP_TYPE: u16 = 21;
39const RTA_ENCAP: u16 = 22;
40const RTA_EXPIRES: u16 = 23;
41const RTA_UID: u16 = 25;
42const RTA_TTL_PROPAGATE: u16 = 26;
43#[derive(Debug, PartialEq, Eq, Clone)]
52#[non_exhaustive]
53pub enum RouteAttribute {
54 Metrics(Vec<RouteMetric>),
55 MfcStats(RouteMfcStats),
56 MultiPath(Vec<RouteNextHop>),
57 CacheInfo(RouteCacheInfo),
58 Destination(RouteAddress),
59 Source(RouteAddress),
60 Gateway(RouteAddress),
61 PrefSource(RouteAddress),
62 Via(RouteVia),
63 NewDestination(Vec<MplsLabel>),
65 Preference(RoutePreference),
66 EncapType(RouteLwEnCapType),
67 Encap(Vec<RouteLwTunnelEncap>),
68 Expires(u32),
73 MulticastExpires(u64),
75 Uid(u32),
76 TtlPropagate(RouteMplsTtlPropagation),
77 Iif(u32),
78 Oif(u32),
79 Priority(u32),
80 Realm(RouteRealm),
82 Table(u32),
83 Mark(u32),
84 Other(DefaultNla),
85}
86
87impl Nla for RouteAttribute {
88 fn value_len(&self) -> usize {
89 match self {
90 Self::Destination(addr)
91 | Self::PrefSource(addr)
92 | Self::Gateway(addr)
93 | Self::Source(addr) => addr.buffer_len(),
94 Self::Via(v) => v.buffer_len(),
95 Self::NewDestination(v) => VecMplsLabel(v.clone()).buffer_len(),
96 Self::Encap(v) => v.as_slice().buffer_len(),
97 Self::TtlPropagate(_) => 1,
98 Self::CacheInfo(cache_info) => cache_info.buffer_len(),
99 Self::MfcStats(stats) => stats.buffer_len(),
100 Self::Metrics(metrics) => metrics.as_slice().buffer_len(),
101 Self::MultiPath(next_hops) => {
102 next_hops.iter().map(|nh| nh.buffer_len()).sum()
103 }
104 Self::Preference(_) => 1,
105 Self::EncapType(v) => v.buffer_len(),
106 Self::Realm(v) => v.buffer_len(),
107 Self::Uid(_)
108 | Self::Expires(_)
109 | Self::Iif(_)
110 | Self::Oif(_)
111 | Self::Priority(_)
112 | Self::Table(_)
113 | Self::Mark(_) => 4,
114 Self::MulticastExpires(_) => 8,
115 Self::Other(attr) => attr.value_len(),
116 }
117 }
118
119 fn emit_value(&self, buffer: &mut [u8]) {
120 match self {
121 Self::Destination(addr)
122 | Self::PrefSource(addr)
123 | Self::Source(addr)
124 | Self::Gateway(addr) => addr.emit(buffer),
125 Self::Via(v) => v.emit(buffer),
126 Self::NewDestination(v) => VecMplsLabel(v.to_vec()).emit(buffer),
127
128 Self::Encap(nlas) => nlas.as_slice().emit(buffer),
129 Self::TtlPropagate(v) => buffer[0] = u8::from(*v),
130 Self::Preference(p) => buffer[0] = (*p).into(),
131 Self::CacheInfo(cache_info) => cache_info.emit(buffer),
132 Self::MfcStats(stats) => stats.emit(buffer),
133 Self::Metrics(metrics) => metrics.as_slice().emit(buffer),
134 Self::MultiPath(next_hops) => {
135 let mut offset = 0;
136 for nh in next_hops {
137 let len = nh.buffer_len();
138 nh.emit(&mut buffer[offset..offset + len]);
139 offset += len
140 }
141 }
142 Self::EncapType(v) => v.emit(buffer),
143 Self::Uid(value)
144 | Self::Expires(value)
145 | Self::Iif(value)
146 | Self::Oif(value)
147 | Self::Priority(value)
148 | Self::Table(value)
149 | Self::Mark(value) => emit_u32(buffer, *value).unwrap(),
150 Self::Realm(v) => v.emit(buffer),
151 Self::MulticastExpires(value) => emit_u64(buffer, *value).unwrap(),
152 Self::Other(attr) => attr.emit_value(buffer),
153 }
154 }
155
156 fn kind(&self) -> u16 {
157 match self {
158 Self::Destination(_) => RTA_DST,
159 Self::Source(_) => RTA_SRC,
160 Self::Iif(_) => RTA_IIF,
161 Self::Oif(_) => RTA_OIF,
162 Self::Gateway(_) => RTA_GATEWAY,
163 Self::Priority(_) => RTA_PRIORITY,
164 Self::PrefSource(_) => RTA_PREFSRC,
165 Self::Metrics(_) => RTA_METRICS,
166 Self::MultiPath(_) => RTA_MULTIPATH,
167 Self::Realm(_) => RTA_FLOW,
168 Self::CacheInfo(_) => RTA_CACHEINFO,
169 Self::Table(_) => RTA_TABLE,
170 Self::Mark(_) => RTA_MARK,
171 Self::MfcStats(_) => RTA_MFC_STATS,
172 Self::Via(_) => RTA_VIA,
173 Self::NewDestination(_) => RTA_NEWDST,
174 Self::Preference(_) => RTA_PREF,
175 Self::EncapType(_) => RTA_ENCAP_TYPE,
176 Self::Encap(_) => RTA_ENCAP,
177 Self::Expires(_) => RTA_EXPIRES,
178 Self::MulticastExpires(_) => RTA_EXPIRES,
179 Self::Uid(_) => RTA_UID,
180 Self::TtlPropagate(_) => RTA_TTL_PROPAGATE,
181 Self::Other(ref attr) => attr.kind(),
182 }
183 }
184
185 fn is_nested(&self) -> bool {
186 if let Self::Encap(encap) = self {
187 encap
188 .iter()
189 .any(|e| matches!(e, RouteLwTunnelEncap::Seg6(_)))
190 } else {
191 false
192 }
193 }
194}
195
196impl<'a, T: AsRef<[u8]> + ?Sized>
197 ParseableParametrized<
198 NlaBuffer<&'a T>,
199 (AddressFamily, RouteType, RouteLwEnCapType),
200 > for RouteAttribute
201{
202 fn parse_with_param(
203 buf: &NlaBuffer<&'a T>,
204 (address_family, route_type, encap_type): (
205 AddressFamily,
206 RouteType,
207 RouteLwEnCapType,
208 ),
209 ) -> Result<Self, DecodeError> {
210 let payload = buf.value();
211 Ok(match buf.kind() {
212 RTA_DST => {
213 Self::Destination(RouteAddress::parse(address_family, payload)?)
214 }
215 RTA_SRC => {
216 Self::Source(RouteAddress::parse(address_family, payload)?)
217 }
218 RTA_GATEWAY => {
219 Self::Gateway(RouteAddress::parse(address_family, payload)?)
220 }
221 RTA_PREFSRC => {
222 Self::PrefSource(RouteAddress::parse(address_family, payload)?)
223 }
224 RTA_VIA => Self::Via(
225 RouteVia::parse(
226 &RouteViaBuffer::new_checked(payload).context(format!(
227 "Invalid RTA_VIA value {payload:?}"
228 ))?,
229 )
230 .context(format!("Invalid RTA_VIA value {payload:?}"))?,
231 ),
232 RTA_NEWDST => Self::NewDestination(
233 VecMplsLabel::parse(payload)
234 .context(format!("Invalid RTA_NEWDST value {payload:?}"))?
235 .0,
236 ),
237
238 RTA_PREF => Self::Preference(parse_u8(payload)?.into()),
239 RTA_ENCAP => Self::Encap(
240 VecRouteLwTunnelEncap::parse_with_param(buf, encap_type)?.0,
241 ),
242 RTA_EXPIRES => {
243 if route_type == RouteType::Multicast {
244 Self::MulticastExpires(parse_u64(payload).context(
245 format!(
246 "invalid RTA_EXPIRES (multicast) value {payload:?}"
247 ),
248 )?)
249 } else {
250 Self::Expires(parse_u32(payload).context(format!(
251 "invalid RTA_EXPIRES value {payload:?}"
252 ))?)
253 }
254 }
255 RTA_UID => Self::Uid(
256 parse_u32(payload)
257 .context(format!("invalid RTA_UID value {payload:?}"))?,
258 ),
259 RTA_TTL_PROPAGATE => Self::TtlPropagate(
260 RouteMplsTtlPropagation::from(parse_u8(payload).context(
261 format!("invalid RTA_TTL_PROPAGATE {payload:?}"),
262 )?),
263 ),
264 RTA_ENCAP_TYPE => Self::EncapType(RouteLwEnCapType::from(
265 parse_u16(payload).context("invalid RTA_ENCAP_TYPE value")?,
266 )),
267 RTA_IIF => {
268 Self::Iif(parse_u32(payload).context("invalid RTA_IIF value")?)
269 }
270 RTA_OIF => {
271 Self::Oif(parse_u32(payload).context("invalid RTA_OIF value")?)
272 }
273 RTA_PRIORITY => Self::Priority(
274 parse_u32(payload).context("invalid RTA_PRIORITY value")?,
275 ),
276 RTA_FLOW => Self::Realm(
277 RouteRealm::parse(payload).context("invalid RTA_FLOW value")?,
278 ),
279 RTA_TABLE => Self::Table(
280 parse_u32(payload).context("invalid RTA_TABLE value")?,
281 ),
282 RTA_MARK => Self::Mark(
283 parse_u32(payload).context("invalid RTA_MARK value")?,
284 ),
285
286 RTA_CACHEINFO => Self::CacheInfo(
287 RouteCacheInfo::parse(
288 &RouteCacheInfoBuffer::new_checked(payload)
289 .context("invalid RTA_CACHEINFO value")?,
290 )
291 .context("invalid RTA_CACHEINFO value")?,
292 ),
293 RTA_MFC_STATS => Self::MfcStats(
294 RouteMfcStats::parse(
295 &RouteMfcStatsBuffer::new_checked(payload)
296 .context("invalid RTA_MFC_STATS value")?,
297 )
298 .context("invalid RTA_MFC_STATS value")?,
299 ),
300 RTA_METRICS => Self::Metrics(
301 VecRouteMetric::parse(payload)
302 .context("invalid RTA_METRICS value")?
303 .0,
304 ),
305 RTA_MULTIPATH => {
306 let mut next_hops = vec![];
307 let mut buf = payload;
308 loop {
309 let nh_buf = RouteNextHopBuffer::new_checked(&buf)
310 .context("invalid RTA_MULTIPATH value")?;
311 let len = nh_buf.length() as usize;
312 let nh = RouteNextHop::parse_with_param(
313 &nh_buf,
314 (address_family, route_type, encap_type),
315 )
316 .context("invalid RTA_MULTIPATH value")?;
317 next_hops.push(nh);
318 if buf.len() == len {
319 break;
320 }
321 buf = &buf[len..];
322 }
323 Self::MultiPath(next_hops)
324 }
325 _ => Self::Other(
326 DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
327 ),
328 })
329 }
330}