netlink_packet_route/neighbour/
attribute.rs

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