netlink_packet_route/rtnl/neighbour/
message.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use netlink_packet_utils::{
5    traits::{Emitable, Parseable},
6    DecodeError,
7};
8
9use crate::{nlas::neighbour::Nla, NeighbourHeader, NeighbourMessageBuffer};
10
11#[derive(Debug, PartialEq, Eq, Clone, Default)]
12#[non_exhaustive]
13pub struct NeighbourMessage {
14    pub header: NeighbourHeader,
15    pub nlas: Vec<Nla>,
16}
17
18impl Emitable for NeighbourMessage {
19    fn buffer_len(&self) -> usize {
20        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
21    }
22
23    fn emit(&self, buffer: &mut [u8]) {
24        self.header.emit(buffer);
25        self.nlas
26            .as_slice()
27            .emit(&mut buffer[self.header.buffer_len()..]);
28    }
29}
30
31impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>>
32    for NeighbourMessage
33{
34    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
35        Ok(NeighbourMessage {
36            header: NeighbourHeader::parse(buf)
37                .context("failed to parse neighbour message header")?,
38            nlas: Vec::<Nla>::parse(buf)
39                .context("failed to parse neighbour message NLAs")?,
40        })
41    }
42}
43
44impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>>
45    for Vec<Nla>
46{
47    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
48        let mut nlas = vec![];
49        for nla_buf in buf.nlas() {
50            nlas.push(Nla::parse(&nla_buf?)?);
51        }
52        Ok(nlas)
53    }
54}
55
56#[cfg(test)]
57mod test {
58    use crate::{
59        constants::*, NeighbourHeader, NeighbourMessage, NeighbourMessageBuffer,
60    };
61    use netlink_packet_utils::traits::Emitable;
62
63    // 0020   0a 00 00 00 02 00 00 00 02 00 80 01 14 00 01 00
64    // 0030   2a 02 80 10 66 d5 00 00 f6 90 ea ff fe 00 2d 83
65    // 0040   0a 00 02 00 f4 90 ea 00 2d 83 00 00 08 00 04 00
66    // 0050   01 00 00 00 14 00 03 00 00 00 00 00 00 00 00 00
67    // 0060   00 00 00 00 02 00 00 00
68
69    #[rustfmt::skip]
70    static HEADER: [u8; 12] = [
71        0x0a, // interface family (inet6)
72        0xff, 0xff, 0xff, // padding
73        0x01, 0x00, 0x00, 0x00, // interface index = 1
74        0x02, 0x00, // state NUD_REACHABLE
75        0x80, // flags NTF_PROXY
76        0x01  // ntype
77
78        // nlas
79        // will add some once I've got them parsed out.
80    ];
81
82    #[test]
83    fn packet_header_read() {
84        let packet = NeighbourMessageBuffer::new(&HEADER[0..12]);
85        assert_eq!(packet.family(), AF_INET6 as u8);
86        assert_eq!(packet.ifindex(), 1);
87        assert_eq!(packet.state(), NUD_REACHABLE);
88        assert_eq!(packet.flags(), NTF_ROUTER);
89        assert_eq!(packet.ntype(), NDA_DST as u8);
90    }
91
92    #[test]
93    fn packet_header_build() {
94        let mut buf = vec![0xff; 12];
95        {
96            let mut packet = NeighbourMessageBuffer::new(&mut buf);
97            packet.set_family(AF_INET6 as u8);
98            packet.set_ifindex(1);
99            packet.set_state(NUD_REACHABLE);
100            packet.set_flags(NTF_ROUTER);
101            packet.set_ntype(NDA_DST as u8);
102        }
103        assert_eq!(&buf[..], &HEADER[0..12]);
104    }
105
106    #[test]
107    fn emit() {
108        let header = NeighbourHeader {
109            family: AF_INET6 as u8,
110            ifindex: 1,
111            state: NUD_REACHABLE,
112            flags: NTF_ROUTER,
113            ntype: NDA_DST as u8,
114        };
115
116        let nlas = vec![];
117        let packet = NeighbourMessage { header, nlas };
118        let mut buf = [0; 12];
119
120        assert_eq!(packet.buffer_len(), 12);
121        packet.emit(&mut buf[..]);
122    }
123}