netlink_packet_route/rtnl/nsid/
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::nsid::Nla, NsidHeader, NsidMessageBuffer};
10
11#[derive(Debug, PartialEq, Eq, Clone, Default)]
12#[non_exhaustive]
13pub struct NsidMessage {
14    pub header: NsidHeader,
15    pub nlas: Vec<Nla>,
16}
17
18impl<'a, T: AsRef<[u8]> + 'a> Parseable<NsidMessageBuffer<&'a T>>
19    for NsidMessage
20{
21    fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
22        Ok(Self {
23            header: NsidHeader::parse(buf)
24                .context("failed to parse nsid message header")?,
25            nlas: Vec::<Nla>::parse(buf)
26                .context("failed to parse nsid message NLAs")?,
27        })
28    }
29}
30
31impl<'a, T: AsRef<[u8]> + 'a> Parseable<NsidMessageBuffer<&'a T>> for Vec<Nla> {
32    fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
33        let mut nlas = vec![];
34        for nla_buf in buf.nlas() {
35            nlas.push(Nla::parse(&nla_buf?)?);
36        }
37        Ok(nlas)
38    }
39}
40
41impl Emitable for NsidMessage {
42    fn buffer_len(&self) -> usize {
43        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
44    }
45
46    fn emit(&self, buffer: &mut [u8]) {
47        self.header.emit(buffer);
48        self.nlas
49            .as_slice()
50            .emit(&mut buffer[self.header.buffer_len()..]);
51    }
52}
53
54#[cfg(test)]
55mod test {
56    use crate::{
57        nlas::nsid::Nla, NsidHeader, NsidMessage, RtnlMessage,
58        RtnlMessageBuffer, NETNSA_NSID_NOT_ASSIGNED, RTM_GETNSID, RTM_NEWNSID,
59    };
60    use netlink_packet_core::NetlinkBuffer;
61    use netlink_packet_utils::traits::ParseableParametrized;
62
63    #[rustfmt::skip]
64    #[test]
65    fn get_ns_id_request() {
66        let data = vec![
67            0x1c, 0x00, 0x00, 0x00, // length = 28
68            0x5a, 0x00, // message type = 90 = RTM_GETNSID
69            0x01, 0x00, // flags
70            0x00, 0x00, 0x00, 0x00, // seq number
71            0x00, 0x00, 0x00, 0x00, // pid
72
73            // GETNSID message
74            0x00, // rtgen family
75            0x00, 0x00, 0x00, // padding
76            // NLA
77            0x08, 0x00, // length = 8
78            0x03, 0x00, // type = 3 (Fd)
79            0x04, 0x00, 0x00, 0x00 // 4
80        ];
81        let expected = RtnlMessage::GetNsId(NsidMessage {
82            header: NsidHeader { rtgen_family: 0 },
83            nlas: vec![Nla::Fd(4)],
84        });
85        let actual = RtnlMessage::parse_with_param(&RtnlMessageBuffer::new(&NetlinkBuffer::new(&data).payload()), RTM_GETNSID).unwrap();
86        assert_eq!(expected, actual);
87    }
88
89    #[rustfmt::skip]
90    #[test]
91    fn get_ns_id_response() {
92        let data = vec![
93            0x1c, 0x00, 0x00, 0x00, // length = 28
94            0x58, 0x00, // message type = RTM_NEWNSID
95            0x00, 0x00, // flags
96            0x00, 0x00, 0x00, 0x00, // seq number
97            0x76, 0x12, 0x00, 0x00, // pid
98
99            // NETNSID message
100            0x00, // rtgen family
101            0x00, 0x00, 0x00, // padding
102            // NLA
103            0x08, 0x00, // length
104            0x01, 0x00, // type = NETNSA_NSID
105            0xff, 0xff, 0xff, 0xff // -1
106        ];
107        let expected = RtnlMessage::NewNsId(NsidMessage {
108            header: NsidHeader { rtgen_family: 0 },
109            nlas: vec![Nla::Id(NETNSA_NSID_NOT_ASSIGNED)],
110        });
111        let nl_buffer = NetlinkBuffer::new(&data).payload();
112        let rtnl_buffer = RtnlMessageBuffer::new(&nl_buffer);
113        let actual = RtnlMessage::parse_with_param(&rtnl_buffer, RTM_NEWNSID).unwrap();
114        assert_eq!(expected, actual);
115    }
116}