netlink_packet_route/route/
attribute.rs

1// SPDX-License-Identifier: MIT
2
3use super::super::AddressFamily;
4use super::lwtunnel::VecRouteLwTunnelEncap;
5use super::metrics::VecRouteMetric;
6use super::mpls::VecMplsLabel;
7use super::{
8    MplsLabel, RouteAddress, RouteCacheInfo, RouteCacheInfoBuffer, RouteError, RouteLwEnCapType,
9    RouteLwTunnelEncap, RouteMetric, RouteMfcStats, RouteMfcStatsBuffer, RouteMplsTtlPropagation,
10    RouteNextHop, RouteNextHopBuffer, RoutePreference, RouteRealm, RouteType, RouteVia,
11    RouteViaBuffer,
12};
13use byteorder::{ByteOrder, NativeEndian};
14use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer};
15use netlink_packet_utils::parsers::{parse_u16, parse_u32, parse_u64, parse_u8};
16use netlink_packet_utils::traits::{Emitable, Parseable, ParseableParametrized};
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;
27// const RTA_PROTOINFO: u16 = 10; // linux kernel said `no longer used`
28const RTA_FLOW: u16 = 11;
29const RTA_CACHEINFO: u16 = 12;
30// const RTA_SESSION: u16 = 13; // linux kernel said `no longer used`
31// const RTA_MP_ALGO: u16 = 14; // linux kernel said `no longer used`
32const 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// TODO
44// const RTA_IP_PROTO:u16 = 27;
45// const RTA_SPORT:u16 = 28;
46// const RTA_DPORT:u16 = 29;
47// const RTA_NH_ID:u16 = 30;
48
49/// Netlink attributes for `RTM_NEWROUTE`, `RTM_DELROUTE`,
50/// `RTM_GETROUTE` netlink messages.
51#[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    /// Only for MPLS for destination label(u32) to forward the packet with
64    NewDestination(Vec<MplsLabel>),
65    Preference(RoutePreference),
66    EncapType(RouteLwEnCapType),
67    Encap(Vec<RouteLwTunnelEncap>),
68    // The RTA_EXPIRES holds different data type in kernel 6.5.8.
69    // For non-multipath route, it is u32 and only used for modifying routes.
70    // For multipath route, it is u64 for querying only.
71    /// This is only for non-multicast route
72    Expires(u32),
73    /// This is only for multicast route
74    MulticastExpires(u64),
75    Uid(u32),
76    TtlPropagate(RouteMplsTtlPropagation),
77    Iif(u32),
78    Oif(u32),
79    Priority(u32),
80    /// IPv4 Realm
81    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) => next_hops.iter().map(|nh| nh.buffer_len()).sum(),
102            Self::Preference(_) => 1,
103            Self::EncapType(v) => v.buffer_len(),
104            Self::Realm(v) => v.buffer_len(),
105            Self::Uid(_)
106            | Self::Expires(_)
107            | Self::Iif(_)
108            | Self::Oif(_)
109            | Self::Priority(_)
110            | Self::Table(_)
111            | Self::Mark(_) => 4,
112            Self::MulticastExpires(_) => 8,
113            Self::Other(attr) => attr.value_len(),
114        }
115    }
116
117    fn emit_value(&self, buffer: &mut [u8]) {
118        match self {
119            Self::Destination(addr)
120            | Self::PrefSource(addr)
121            | Self::Source(addr)
122            | Self::Gateway(addr) => addr.emit(buffer),
123            Self::Via(v) => v.emit(buffer),
124            Self::NewDestination(v) => VecMplsLabel(v.to_vec()).emit(buffer),
125
126            Self::Encap(nlas) => nlas.as_slice().emit(buffer),
127            Self::TtlPropagate(v) => buffer[0] = u8::from(*v),
128            Self::Preference(p) => buffer[0] = (*p).into(),
129            Self::CacheInfo(cache_info) => cache_info.emit(buffer),
130            Self::MfcStats(stats) => stats.emit(buffer),
131            Self::Metrics(metrics) => metrics.as_slice().emit(buffer),
132            Self::MultiPath(next_hops) => {
133                let mut offset = 0;
134                for nh in next_hops {
135                    let len = nh.buffer_len();
136                    nh.emit(&mut buffer[offset..offset + len]);
137                    offset += len
138                }
139            }
140            Self::EncapType(v) => v.emit(buffer),
141            Self::Uid(value)
142            | Self::Expires(value)
143            | Self::Iif(value)
144            | Self::Oif(value)
145            | Self::Priority(value)
146            | Self::Table(value)
147            | Self::Mark(value) => NativeEndian::write_u32(buffer, *value),
148            Self::Realm(v) => v.emit(buffer),
149            Self::MulticastExpires(value) => NativeEndian::write_u64(buffer, *value),
150            Self::Other(attr) => attr.emit_value(buffer),
151        }
152    }
153
154    fn kind(&self) -> u16 {
155        match self {
156            Self::Destination(_) => RTA_DST,
157            Self::Source(_) => RTA_SRC,
158            Self::Iif(_) => RTA_IIF,
159            Self::Oif(_) => RTA_OIF,
160            Self::Gateway(_) => RTA_GATEWAY,
161            Self::Priority(_) => RTA_PRIORITY,
162            Self::PrefSource(_) => RTA_PREFSRC,
163            Self::Metrics(_) => RTA_METRICS,
164            Self::MultiPath(_) => RTA_MULTIPATH,
165            Self::Realm(_) => RTA_FLOW,
166            Self::CacheInfo(_) => RTA_CACHEINFO,
167            Self::Table(_) => RTA_TABLE,
168            Self::Mark(_) => RTA_MARK,
169            Self::MfcStats(_) => RTA_MFC_STATS,
170            Self::Via(_) => RTA_VIA,
171            Self::NewDestination(_) => RTA_NEWDST,
172            Self::Preference(_) => RTA_PREF,
173            Self::EncapType(_) => RTA_ENCAP_TYPE,
174            Self::Encap(_) => RTA_ENCAP,
175            Self::Expires(_) => RTA_EXPIRES,
176            Self::MulticastExpires(_) => RTA_EXPIRES,
177            Self::Uid(_) => RTA_UID,
178            Self::TtlPropagate(_) => RTA_TTL_PROPAGATE,
179            Self::Other(ref attr) => attr.kind(),
180        }
181    }
182}
183
184impl<'a, T: AsRef<[u8]> + ?Sized>
185    ParseableParametrized<NlaBuffer<&'a T>, (AddressFamily, RouteType, RouteLwEnCapType)>
186    for RouteAttribute
187{
188    type Error = RouteError;
189    fn parse_with_param(
190        buf: &NlaBuffer<&'a T>,
191        (address_family, route_type, encap_type): (AddressFamily, RouteType, RouteLwEnCapType),
192    ) -> Result<Self, RouteError> {
193        let payload = buf.value();
194        Ok(match buf.kind() {
195            RTA_DST => Self::Destination(
196                RouteAddress::parse(address_family, payload)
197                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_DST", error })?,
198            ),
199            RTA_SRC => Self::Source(
200                RouteAddress::parse(address_family, payload)
201                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_SRC", error })?,
202            ),
203            RTA_GATEWAY => Self::Gateway(
204                RouteAddress::parse(address_family, payload)
205                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_GATEWAY", error })?,
206            ),
207            RTA_PREFSRC => Self::PrefSource(
208                RouteAddress::parse(address_family, payload)
209                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_PREFSRC", error })?,
210            ),
211            RTA_VIA => Self::Via(
212                RouteVia::parse(
213                    &RouteViaBuffer::new_checked(payload)
214                        .map_err(|error| RouteError::InvalidValue { kind: "RTA_VIA", error })?,
215                )
216                .map_err(|error| RouteError::InvalidValue { kind: "RTA_VIA", error })?,
217            ),
218            RTA_NEWDST => Self::NewDestination(VecMplsLabel::parse(payload)?.0),
219
220            RTA_PREF => Self::Preference(
221                parse_u8(payload)
222                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_PREF", error })?
223                    .into(),
224            ),
225            RTA_ENCAP => Self::Encap(VecRouteLwTunnelEncap::parse_with_param(buf, encap_type)?.0),
226            RTA_EXPIRES => {
227                if route_type == RouteType::Multicast {
228                    Self::MulticastExpires(parse_u64(payload).map_err(|error| {
229                        RouteError::InvalidValue { kind: "RTA_EXPIRES (multicast)", error }
230                    })?)
231                } else {
232                    Self::Expires(
233                        parse_u32(payload).map_err(|error| RouteError::InvalidValue {
234                            kind: "RTA_EXPIRES",
235                            error,
236                        })?,
237                    )
238                }
239            }
240            RTA_UID => Self::Uid(
241                parse_u32(payload)
242                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_UID", error })?,
243            ),
244            RTA_TTL_PROPAGATE => {
245                Self::TtlPropagate(RouteMplsTtlPropagation::from(parse_u8(payload).map_err(
246                    |error| RouteError::InvalidValue { kind: "RTA_TTL_PROPAGATE", error },
247                )?))
248            }
249            RTA_ENCAP_TYPE => Self::EncapType(RouteLwEnCapType::from(
250                parse_u16(payload)
251                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_ENCAP_TYPE", error })?,
252            )),
253            RTA_IIF => Self::Iif(
254                parse_u32(payload)
255                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_IIF", error })?,
256            ),
257            RTA_OIF => Self::Oif(
258                parse_u32(payload)
259                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_OIF", error })?,
260            ),
261            RTA_PRIORITY => Self::Priority(
262                parse_u32(payload)
263                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_PRIORITY", error })?,
264            ),
265            RTA_FLOW => Self::Realm(RouteRealm::parse(payload)?),
266            RTA_TABLE => Self::Table(
267                parse_u32(payload)
268                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_TABLE", error })?,
269            ),
270            RTA_MARK => Self::Mark(
271                parse_u32(payload)
272                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_MARK", error })?,
273            ),
274
275            RTA_CACHEINFO => {
276                Self::CacheInfo(
277                    RouteCacheInfo::parse(&RouteCacheInfoBuffer::new_checked(payload).map_err(
278                        |error| RouteError::InvalidValue { kind: "RTA_CACHEINFO", error },
279                    )?)
280                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_CACHEINFO", error })?,
281                )
282            }
283            RTA_MFC_STATS => {
284                Self::MfcStats(
285                    RouteMfcStats::parse(&RouteMfcStatsBuffer::new_checked(payload).map_err(
286                        |error| RouteError::InvalidValue { kind: "RTA_MFC_STATS", error },
287                    )?)
288                    .map_err(|error| RouteError::InvalidValue { kind: "RTA_MFC_STATS", error })?,
289                )
290            }
291            RTA_METRICS => Self::Metrics(VecRouteMetric::parse(payload)?.0),
292            RTA_MULTIPATH => {
293                let mut next_hops = vec![];
294                let mut buf = payload;
295                loop {
296                    let nh_buf = RouteNextHopBuffer::new_checked(&buf).map_err(|error| {
297                        RouteError::InvalidValue { kind: "RTA_MULTIPATH", error }
298                    })?;
299                    let len = nh_buf.length() as usize;
300                    let nh = RouteNextHop::parse_with_param(
301                        &nh_buf,
302                        (address_family, route_type, encap_type),
303                    )?;
304                    next_hops.push(nh);
305                    if buf.len() == len {
306                        break;
307                    }
308                    buf = &buf[len..];
309                }
310                Self::MultiPath(next_hops)
311            }
312            _ => {
313                Self::Other(DefaultNla::parse(buf).map_err(|error| RouteError::InvalidValue {
314                    kind: "NLA (uknown kind)",
315                    error,
316                })?)
317            }
318        })
319    }
320}