netlink_packet_route/rtnl/link/
message.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4
5use crate::{
6    nlas::link::Nla,
7    traits::{Emitable, Parseable, ParseableParametrized},
8    DecodeError,
9    LinkHeader,
10    LinkMessageBuffer,
11};
12
13#[derive(Debug, PartialEq, Eq, Clone, Default)]
14pub struct LinkMessage {
15    pub header: LinkHeader,
16    pub nlas: Vec<Nla>,
17}
18
19impl Emitable for LinkMessage {
20    fn buffer_len(&self) -> usize {
21        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
22    }
23
24    fn emit(&self, buffer: &mut [u8]) {
25        self.header.emit(buffer);
26        self.nlas
27            .as_slice()
28            .emit(&mut buffer[self.header.buffer_len()..]);
29    }
30}
31
32impl<'a, T: AsRef<[u8]> + 'a> Parseable<LinkMessageBuffer<&'a T>> for LinkMessage {
33    fn parse(buf: &LinkMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
34        let header = LinkHeader::parse(buf).context("failed to parse link message header")?;
35        let interface_family = header.interface_family;
36        let nlas = Vec::<Nla>::parse_with_param(buf, interface_family)
37            .context("failed to parse link message NLAs")?;
38        Ok(LinkMessage { header, nlas })
39    }
40}
41
42impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized<LinkMessageBuffer<&'a T>, u16> for Vec<Nla> {
43    fn parse_with_param(buf: &LinkMessageBuffer<&'a T>, family: u16) -> Result<Self, DecodeError> {
44        let mut nlas = vec![];
45        for nla_buf in buf.nlas() {
46            nlas.push(Nla::parse_with_param(&nla_buf?, family)?);
47        }
48        Ok(nlas)
49    }
50}
51
52impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized<LinkMessageBuffer<&'a T>, u8> for Vec<Nla> {
53    fn parse_with_param(buf: &LinkMessageBuffer<&'a T>, family: u8) -> Result<Self, DecodeError> {
54        Vec::<Nla>::parse_with_param(buf, u16::from(family))
55    }
56}
57
58#[cfg(test)]
59mod test {
60    use crate::{
61        constants::*,
62        nlas::link::{Nla, State},
63        traits::{Emitable, ParseableParametrized},
64        LinkHeader,
65        LinkMessage,
66        LinkMessageBuffer,
67    };
68
69    #[rustfmt::skip]
70    static HEADER: [u8; 96] = [
71        0x00, // interface family
72        0x00, // reserved
73        0x04, 0x03, // link layer type 772 = loopback
74        0x01, 0x00, 0x00, 0x00, // interface index = 1
75        // Note: in the wireshark capture, the thrid byte is 0x01
76        // but that does not correpond to any of the IFF_ flags...
77        0x49, 0x00, 0x00, 0x00, // device flags: UP, LOOPBACK, RUNNING, LOWERUP
78        0x00, 0x00, 0x00, 0x00, // reserved 2 (aka device change flag)
79
80        // nlas
81        0x07, 0x00, 0x03, 0x00, 0x6c, 0x6f, 0x00, // device name L=7,T=3,V=lo
82        0x00, // padding
83        0x08, 0x00, 0x0d, 0x00, 0xe8, 0x03, 0x00, 0x00, // TxQueue length L=8,T=13,V=1000
84        0x05, 0x00, 0x10, 0x00, 0x00, // OperState L=5,T=16,V=0 (unknown)
85        0x00, 0x00, 0x00, // padding
86        0x05, 0x00, 0x11, 0x00, 0x00, // Link mode L=5,T=17,V=0
87        0x00, 0x00, 0x00, // padding
88        0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, // MTU L=8,T=4,V=65536
89        0x08, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, // Group L=8,T=27,V=9
90        0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, // Promiscuity L=8,T=30,V=0
91        0x08, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, // Number of Tx Queues L=8,T=31,V=1
92        0x08, 0x00, 0x28, 0x00, 0xff, 0xff, 0x00, 0x00, // Maximum GSO segment count L=8,T=40,V=65536
93        0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, // Maximum GSO size L=8,T=41,V=65536
94    ];
95
96    #[test]
97    fn packet_header_read() {
98        let packet = LinkMessageBuffer::new(&HEADER[0..16]);
99        assert_eq!(packet.interface_family(), 0);
100        assert_eq!(packet.reserved_1(), 0);
101        assert_eq!(packet.link_layer_type(), ARPHRD_LOOPBACK);
102        assert_eq!(packet.link_index(), 1);
103        assert_eq!(packet.flags(), IFF_UP | IFF_LOOPBACK | IFF_RUNNING);
104        assert_eq!(packet.change_mask(), 0);
105    }
106
107    #[test]
108    fn packet_header_build() {
109        let mut buf = vec![0xff; 16];
110        {
111            let mut packet = LinkMessageBuffer::new(&mut buf);
112            packet.set_interface_family(0);
113            packet.set_reserved_1(0);
114            packet.set_link_layer_type(ARPHRD_LOOPBACK);
115            packet.set_link_index(1);
116            packet.set_flags(IFF_UP | IFF_LOOPBACK | IFF_RUNNING);
117            packet.set_change_mask(0);
118        }
119        assert_eq!(&buf[..], &HEADER[0..16]);
120    }
121
122    #[test]
123    fn packet_nlas_read() {
124        let packet = LinkMessageBuffer::new(&HEADER[..]);
125        assert_eq!(packet.nlas().count(), 10);
126        let mut nlas = packet.nlas();
127
128        // device name L=7,T=3,V=lo
129        let nla = nlas.next().unwrap().unwrap();
130        nla.check_buffer_length().unwrap();
131        assert_eq!(nla.length(), 7);
132        assert_eq!(nla.kind(), 3);
133        assert_eq!(nla.value(), &[0x6c, 0x6f, 0x00]);
134        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
135        assert_eq!(parsed, Nla::IfName(String::from("lo")));
136
137        // TxQueue length L=8,T=13,V=1000
138        let nla = nlas.next().unwrap().unwrap();
139        nla.check_buffer_length().unwrap();
140        assert_eq!(nla.length(), 8);
141        assert_eq!(nla.kind(), 13);
142        assert_eq!(nla.value(), &[0xe8, 0x03, 0x00, 0x00]);
143        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
144        assert_eq!(parsed, Nla::TxQueueLen(1000));
145
146        // OperState L=5,T=16,V=0 (unknown)
147        let nla = nlas.next().unwrap().unwrap();
148        nla.check_buffer_length().unwrap();
149        assert_eq!(nla.length(), 5);
150        assert_eq!(nla.kind(), 16);
151        assert_eq!(nla.value(), &[0x00]);
152        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
153        assert_eq!(parsed, Nla::OperState(State::Unknown));
154
155        // Link mode L=5,T=17,V=0
156        let nla = nlas.next().unwrap().unwrap();
157        nla.check_buffer_length().unwrap();
158        assert_eq!(nla.length(), 5);
159        assert_eq!(nla.kind(), 17);
160        assert_eq!(nla.value(), &[0x00]);
161        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
162        assert_eq!(parsed, Nla::Mode(0));
163
164        // MTU L=8,T=4,V=65536
165        let nla = nlas.next().unwrap().unwrap();
166        nla.check_buffer_length().unwrap();
167        assert_eq!(nla.length(), 8);
168        assert_eq!(nla.kind(), 4);
169        assert_eq!(nla.value(), &[0x00, 0x00, 0x01, 0x00]);
170        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
171        assert_eq!(parsed, Nla::Mtu(65_536));
172
173        // 0x00, 0x00, 0x00, 0x00,
174        // Group L=8,T=27,V=9
175        let nla = nlas.next().unwrap().unwrap();
176        nla.check_buffer_length().unwrap();
177        assert_eq!(nla.length(), 8);
178        assert_eq!(nla.kind(), 27);
179        assert_eq!(nla.value(), &[0x00, 0x00, 0x00, 0x00]);
180        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
181        assert_eq!(parsed, Nla::Group(0));
182
183        // Promiscuity L=8,T=30,V=0
184        let nla = nlas.next().unwrap().unwrap();
185        nla.check_buffer_length().unwrap();
186        assert_eq!(nla.length(), 8);
187        assert_eq!(nla.kind(), 30);
188        assert_eq!(nla.value(), &[0x00, 0x00, 0x00, 0x00]);
189        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
190        assert_eq!(parsed, Nla::Promiscuity(0));
191
192        // Number of Tx Queues L=8,T=31,V=1
193        // 0x01, 0x00, 0x00, 0x00
194        let nla = nlas.next().unwrap().unwrap();
195        nla.check_buffer_length().unwrap();
196        assert_eq!(nla.length(), 8);
197        assert_eq!(nla.kind(), 31);
198        assert_eq!(nla.value(), &[0x01, 0x00, 0x00, 0x00]);
199        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();
200        assert_eq!(parsed, Nla::NumTxQueues(1));
201    }
202
203    #[test]
204    fn emit() {
205        let header = LinkHeader {
206            link_layer_type: ARPHRD_LOOPBACK,
207            index: 1,
208            flags: IFF_UP | IFF_LOOPBACK | IFF_RUNNING | IFF_LOWER_UP,
209            ..Default::default()
210        };
211
212        let nlas = vec![
213            Nla::IfName("lo".into()),
214            Nla::TxQueueLen(1000),
215            Nla::OperState(State::Unknown),
216            Nla::Mode(0),
217            Nla::Mtu(0x1_0000),
218            Nla::Group(0),
219            Nla::Promiscuity(0),
220            Nla::NumTxQueues(1),
221            Nla::GsoMaxSegs(0xffff),
222            Nla::GsoMaxSize(0x1_0000),
223        ];
224
225        let packet = LinkMessage { header, nlas };
226
227        let mut buf = vec![0; 96];
228
229        assert_eq!(packet.buffer_len(), 96);
230        packet.emit(&mut buf[..]);
231    }
232}