netlink_packet_route/route/
message.rs

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