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