netlink_packet_route/neighbour/
attribute.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use byteorder::{BigEndian, ByteOrder, NativeEndian};
5use netlink_packet_utils::{
6    nla::{DefaultNla, Nla, NlaBuffer},
7    parsers::{parse_u16, parse_u16_be, parse_u32},
8    DecodeError, Emitable, Parseable, ParseableParametrized,
9};
10
11use super::{NeighbourAddress, NeighbourCacheInfo, NeighbourCacheInfoBuffer};
12use crate::{route::RouteProtocol, AddressFamily};
13
14const NDA_DST: u16 = 1;
15const NDA_LLADDR: u16 = 2;
16const NDA_CACHEINFO: u16 = 3;
17const NDA_PROBES: u16 = 4;
18const NDA_VLAN: u16 = 5;
19const NDA_PORT: u16 = 6;
20const NDA_VNI: u16 = 7;
21const NDA_IFINDEX: u16 = 8;
22// Kernel constant name is NDA_MASTER
23const NDA_CONTROLLER: u16 = 9;
24const NDA_LINK_NETNSID: u16 = 10;
25const NDA_SRC_VNI: u16 = 11;
26const NDA_PROTOCOL: u16 = 12;
27// const NDA_NH_ID: u16 = 13;
28// const NDA_FDB_EXT_ATTRS: u16 = 14;
29
30#[derive(Debug, PartialEq, Eq, Clone)]
31#[non_exhaustive]
32pub enum NeighbourAttribute {
33    Destination(NeighbourAddress),
34    LinkLocalAddress(Vec<u8>),
35    CacheInfo(NeighbourCacheInfo),
36    Probes(u32),
37    Vlan(u16),
38    Port(u16),
39    Vni(u32),
40    IfIndex(u32),
41    Controller(u32),
42    LinkNetNsId(u32),
43    SourceVni(u32),
44    Protocol(RouteProtocol),
45    Other(DefaultNla),
46}
47
48impl Nla for NeighbourAttribute {
49    fn value_len(&self) -> usize {
50        match self {
51            Self::LinkLocalAddress(bytes) => bytes.len(),
52            Self::Destination(v) => v.buffer_len(),
53            Self::CacheInfo(v) => v.buffer_len(),
54            Self::Vlan(_) | Self::Port(_) => 2,
55            Self::Protocol(v) => v.buffer_len(),
56            Self::Probes(_)
57            | Self::LinkNetNsId(_)
58            | Self::Controller(_)
59            | Self::Vni(_)
60            | Self::IfIndex(_)
61            | Self::SourceVni(_) => 4,
62            Self::Other(attr) => attr.value_len(),
63        }
64    }
65
66    fn emit_value(&self, buffer: &mut [u8]) {
67        match self {
68            Self::Destination(v) => v.emit(buffer),
69            Self::LinkLocalAddress(bytes) => {
70                buffer.copy_from_slice(bytes.as_slice())
71            }
72            Self::CacheInfo(v) => v.emit(buffer),
73            Self::Vlan(value) => NativeEndian::write_u16(buffer, *value),
74            Self::Port(value) => BigEndian::write_u16(buffer, *value),
75            Self::Probes(value)
76            | Self::LinkNetNsId(value)
77            | Self::Controller(value)
78            | Self::Vni(value)
79            | Self::IfIndex(value)
80            | Self::SourceVni(value) => NativeEndian::write_u32(buffer, *value),
81            Self::Protocol(v) => v.emit(buffer),
82            Self::Other(attr) => attr.emit_value(buffer),
83        }
84    }
85
86    fn kind(&self) -> u16 {
87        match self {
88            Self::Destination(_) => NDA_DST,
89            Self::LinkLocalAddress(_) => NDA_LLADDR,
90            Self::CacheInfo(_) => NDA_CACHEINFO,
91            Self::Probes(_) => NDA_PROBES,
92            Self::Vlan(_) => NDA_VLAN,
93            Self::Port(_) => NDA_PORT,
94            Self::Vni(_) => NDA_VNI,
95            Self::IfIndex(_) => NDA_IFINDEX,
96            Self::Controller(_) => NDA_CONTROLLER,
97            Self::LinkNetNsId(_) => NDA_LINK_NETNSID,
98            Self::SourceVni(_) => NDA_SRC_VNI,
99            Self::Protocol(_) => NDA_PROTOCOL,
100            Self::Other(nla) => nla.kind(),
101        }
102    }
103}
104
105impl<'a, T: AsRef<[u8]> + ?Sized>
106    ParseableParametrized<NlaBuffer<&'a T>, AddressFamily>
107    for NeighbourAttribute
108{
109    fn parse_with_param(
110        buf: &NlaBuffer<&'a T>,
111        address_family: AddressFamily,
112    ) -> Result<Self, DecodeError> {
113        let payload = buf.value();
114        Ok(match buf.kind() {
115            NDA_DST => Self::Destination(
116                NeighbourAddress::parse_with_param(address_family, payload)
117                    .context(format!("invalid NDA_DST value {:?}", payload))?,
118            ),
119            NDA_LLADDR => Self::LinkLocalAddress(payload.to_vec()),
120            NDA_CACHEINFO => Self::CacheInfo(
121                NeighbourCacheInfo::parse(
122                    &NeighbourCacheInfoBuffer::new_checked(payload).context(
123                        format!("invalid NDA_CACHEINFO value {:?}", payload),
124                    )?,
125                )
126                .context(format!(
127                    "invalid NDA_CACHEINFO value {:?}",
128                    payload
129                ))?,
130            ),
131            NDA_PROBES => {
132                Self::Probes(parse_u32(payload).context(format!(
133                    "invalid NDA_PROBES value {:?}",
134                    payload
135                ))?)
136            }
137            NDA_VLAN => Self::Vlan(parse_u16(payload)?),
138            NDA_PORT => Self::Port(
139                parse_u16_be(payload)
140                    .context(format!("invalid NDA_PORT value {payload:?}"))?,
141            ),
142            NDA_VNI => Self::Vni(parse_u32(payload)?),
143            NDA_IFINDEX => Self::IfIndex(parse_u32(payload)?),
144            NDA_CONTROLLER => Self::Controller(parse_u32(payload).context(
145                format!("invalid NDA_CONTROLLER value {payload:?}"),
146            )?),
147            NDA_LINK_NETNSID => Self::LinkNetNsId(parse_u32(payload).context(
148                format!("invalid NDA_LINK_NETNSID value {payload:?}"),
149            )?),
150            NDA_SRC_VNI => Self::SourceVni(parse_u32(payload)?),
151            NDA_PROTOCOL => {
152                Self::Protocol(RouteProtocol::parse(payload).context(
153                    format!("invalid NDA_PROTOCOL value {:?}", payload),
154                )?)
155            }
156            _ => Self::Other(
157                DefaultNla::parse(buf)
158                    .context("invalid link NLA value (unknown type)")?,
159            ),
160        })
161    }
162}