netlink_packet_route/route/
message.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    DecodeError, Emitable, ErrorContext, Parseable, ParseableParametrized,
5};
6
7use super::{
8    super::AddressFamily, attribute::RTA_ENCAP_TYPE, RouteAttribute,
9    RouteHeader, RouteLwEnCapType, RouteMessageBuffer, RouteType,
10};
11
12#[derive(Debug, PartialEq, Eq, Clone, Default)]
13#[non_exhaustive]
14pub struct RouteMessage {
15    pub header: RouteHeader,
16    pub attributes: Vec<RouteAttribute>,
17}
18
19impl Emitable for RouteMessage {
20    fn buffer_len(&self) -> usize {
21        self.header.buffer_len() + self.attributes.as_slice().buffer_len()
22    }
23
24    fn emit(&self, buffer: &mut [u8]) {
25        self.header.emit(buffer);
26        self.attributes
27            .as_slice()
28            .emit(&mut buffer[self.header.buffer_len()..]);
29    }
30}
31
32impl<'a, T: AsRef<[u8]> + 'a> Parseable<RouteMessageBuffer<&'a T>>
33    for RouteMessage
34{
35    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
36        let header = RouteHeader::parse(buf)
37            .context("failed to parse route message header")?;
38        let address_family = header.address_family;
39        let route_type = header.kind;
40        Ok(RouteMessage {
41            header,
42            attributes: Vec::<RouteAttribute>::parse_with_param(
43                buf,
44                (address_family, route_type),
45            )
46            .context("failed to parse route message NLAs")?,
47        })
48    }
49}
50
51impl<'a, T: AsRef<[u8]> + 'a>
52    ParseableParametrized<RouteMessageBuffer<&'a T>, (AddressFamily, RouteType)>
53    for Vec<RouteAttribute>
54{
55    fn parse_with_param(
56        buf: &RouteMessageBuffer<&'a T>,
57        (address_family, route_type): (AddressFamily, RouteType),
58    ) -> Result<Self, DecodeError> {
59        let mut attributes = vec![];
60        let mut encap_type = RouteLwEnCapType::None;
61        // The RTA_ENCAP_TYPE is provided __after__ RTA_ENCAP, we should find
62        // RTA_ENCAP_TYPE first.
63        for nla_buf in buf.attributes() {
64            let nla = match nla_buf {
65                Ok(n) => n,
66                Err(_) => continue,
67            };
68            if nla.kind() == RTA_ENCAP_TYPE {
69                if let Ok(RouteAttribute::EncapType(v)) =
70                    RouteAttribute::parse_with_param(
71                        &nla,
72                        (address_family, route_type, encap_type),
73                    )
74                {
75                    encap_type = v;
76                    break;
77                }
78            }
79        }
80        for nla_buf in buf.attributes() {
81            attributes.push(RouteAttribute::parse_with_param(
82                &nla_buf?,
83                (address_family, route_type, encap_type),
84            )?);
85        }
86        Ok(attributes)
87    }
88}