1use std::{convert::TryFrom, mem::size_of, os::fd::RawFd};
4
5use anyhow::Context;
6use byteorder::{ByteOrder, NativeEndian};
7use netlink_packet_utils::{
8 nla::{DefaultNla, Nla, NlaBuffer, NlasIterator},
9 parsers::{parse_i32, parse_u32},
10 DecodeError, Parseable,
11};
12
13use crate::constants::*;
14
15#[non_exhaustive]
16#[derive(Debug, PartialEq, Eq, Clone)]
17pub enum Xdp {
18 Fd(RawFd),
19 Attached(XdpAttached),
20 Flags(u32),
21 ProgId(u32),
22 DrvProgId(u32),
23 SkbProgId(u32),
24 HwProgId(u32),
25 ExpectedFd(u32),
26 Other(DefaultNla),
27}
28
29impl Nla for Xdp {
30 #[rustfmt::skip]
31 fn value_len(&self) -> usize {
32 use self::Xdp::*;
33 match self {
34 Fd(_) => size_of::<RawFd>(),
35 Attached(_) => size_of::<u8>(),
36 Flags(_) => size_of::<u32>(),
37 ProgId(_) => size_of::<u32>(),
38 DrvProgId(_) => size_of::<u32>(),
39 SkbProgId(_) => size_of::<u32>(),
40 HwProgId(_) => size_of::<u32>(),
41 ExpectedFd(_) => size_of::<u32>(),
42 Other(nla) => nla.value_len()
43 }
44 }
45
46 #[rustfmt::skip]
47 fn emit_value(&self, buffer: &mut [u8]) {
48 use self::Xdp::*;
49 match self {
50 Fd(ref value) => NativeEndian::write_i32(buffer, *value),
51 Attached(ref value) => buffer[0] = value.as_u8(),
52 Flags(ref value) => NativeEndian::write_u32(buffer, *value),
53 ProgId(ref value) => NativeEndian::write_u32(buffer, *value),
54 DrvProgId(ref value) => NativeEndian::write_u32(buffer, *value),
55 SkbProgId(ref value) => NativeEndian::write_u32(buffer, *value),
56 HwProgId(ref value) => NativeEndian::write_u32(buffer, *value),
57 ExpectedFd(ref value) => NativeEndian::write_u32(buffer, *value),
58 Other(ref nla) => nla.emit_value(buffer)
59 }
60 }
61
62 fn kind(&self) -> u16 {
63 use self::Xdp::*;
64 match self {
65 Fd(_) => IFLA_XDP_FD as u16,
66 Attached(_) => IFLA_XDP_ATTACHED as u16,
67 Flags(_) => IFLA_XDP_FLAGS as u16,
68 ProgId(_) => IFLA_XDP_PROG_ID as u16,
69 DrvProgId(_) => IFLA_XDP_DRV_PROG_ID as u16,
70 SkbProgId(_) => IFLA_XDP_SKB_PROG_ID as u16,
71 HwProgId(_) => IFLA_XDP_HW_PROG_ID as u16,
72 ExpectedFd(_) => IFLA_XDP_EXPECTED_FD as u16,
73 Other(nla) => nla.kind(),
74 }
75 }
76}
77
78pub(crate) struct VecXdp(pub(crate) Vec<Xdp>);
79
80impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecXdp {
87 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
88 let mut res = Vec::new();
89 let nlas = NlasIterator::new(buf.into_inner());
90 for nla in nlas {
91 let nla = nla?;
92 match nla.kind() as u32 {
93 IFLA_XDP_FD => res.push(Xdp::Fd(
94 parse_i32(nla.value())
95 .context("invalid IFLA_XDP_FD value")?,
96 )),
97 IFLA_XDP_ATTACHED => res.push(Xdp::Attached(
98 XdpAttached::try_from(nla.value()[0])
99 .context("invalid IFLA_XDP_ATTACHED value")?,
100 )),
101 IFLA_XDP_FLAGS => res.push(Xdp::Flags(
102 parse_u32(nla.value())
103 .context("invalid IFLA_XDP_FLAGS value")?,
104 )),
105 IFLA_XDP_PROG_ID => res.push(Xdp::ProgId(
106 parse_u32(nla.value())
107 .context("invalid IFLA_XDP_PROG_ID value")?,
108 )),
109 IFLA_XDP_DRV_PROG_ID => res.push(Xdp::DrvProgId(
110 parse_u32(nla.value())
111 .context("invalid IFLA_XDP_PROG_ID value")?,
112 )),
113 IFLA_XDP_SKB_PROG_ID => res.push(Xdp::SkbProgId(
114 parse_u32(nla.value())
115 .context("invalid IFLA_XDP_PROG_ID value")?,
116 )),
117 IFLA_XDP_HW_PROG_ID => res.push(Xdp::HwProgId(
118 parse_u32(nla.value())
119 .context("invalid IFLA_XDP_PROG_ID value")?,
120 )),
121 IFLA_XDP_EXPECTED_FD => res.push(Xdp::ExpectedFd(
122 parse_u32(nla.value())
123 .context("invalid IFLA_XDP_PROG_ID value")?,
124 )),
125 _ => res
126 .push(Xdp::Other(DefaultNla::parse(&nla).context(
127 format!("unknown NLA type {}", nla.kind()),
128 )?)),
129 }
130 }
131 Ok(VecXdp(res))
132 }
133}
134
135#[non_exhaustive]
136#[derive(Debug, PartialEq, Eq, Clone, Copy)]
137pub enum XdpAttached {
138 None,
140 Driver,
142 SocketBuffer,
144 Hardware,
146 Multiple,
148 Other(u8),
150}
151
152impl TryFrom<u8> for XdpAttached {
153 type Error = DecodeError;
154
155 fn try_from(value: u8) -> Result<Self, Self::Error> {
156 match value {
157 XDP_ATTACHED_NONE => Ok(XdpAttached::None),
158 XDP_ATTACHED_DRV => Ok(XdpAttached::Driver),
159 XDP_ATTACHED_SKB => Ok(XdpAttached::SocketBuffer),
160 XDP_ATTACHED_HW => Ok(XdpAttached::Hardware),
161 XDP_ATTACHED_MULTI => Ok(XdpAttached::Multiple),
162 _ => Ok(XdpAttached::Other(value)),
163 }
164 }
165}
166
167impl XdpAttached {
168 fn as_u8(&self) -> u8 {
169 match self {
170 XdpAttached::None => XDP_ATTACHED_NONE,
171 XdpAttached::Driver => XDP_ATTACHED_DRV,
172 XdpAttached::SocketBuffer => XDP_ATTACHED_SKB,
173 XdpAttached::Hardware => XDP_ATTACHED_HW,
174 XdpAttached::Multiple => XDP_ATTACHED_MULTI,
175 XdpAttached::Other(other) => *other,
176 }
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use netlink_packet_utils::Emitable;
183
184 use super::*;
185
186 #[rustfmt::skip]
187 static ATTACHED: [u8; 48] = [
188 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0xfc, 0x00, 0x00, 0x00, ];
213
214 #[test]
215 fn parse_xdp_attached() {
216 let nla = NlaBuffer::new_checked(&ATTACHED[..]).unwrap();
217 let parsed = VecXdp::parse(&nla).unwrap().0;
218 let expected = vec![
219 Xdp::Attached(XdpAttached::None),
220 Xdp::Attached(XdpAttached::Driver),
221 Xdp::Attached(XdpAttached::SocketBuffer),
222 Xdp::Attached(XdpAttached::Hardware),
223 Xdp::Attached(XdpAttached::Multiple),
224 Xdp::Attached(XdpAttached::Other(252)),
225 ];
226 assert_eq!(expected, parsed);
227 }
228
229 #[test]
230 fn emit_xdp_attached() {
231 let nlas = vec![Xdp::Attached(XdpAttached::None)];
233 assert_eq!(nlas.as_slice().buffer_len(), 8);
234
235 let mut vec = vec![0xff; 8];
236 nlas.as_slice().emit(&mut vec);
237 assert_eq!(&vec[..], &ATTACHED[..8]);
238
239 let nlas = vec![Xdp::Attached(XdpAttached::Driver)];
241 assert_eq!(nlas.as_slice().buffer_len(), 8);
242
243 let mut vec = vec![0xff; 8];
244 nlas.as_slice().emit(&mut vec);
245 assert_eq!(&vec[..], &ATTACHED[8..16]);
246
247 let nlas = vec![Xdp::Attached(XdpAttached::SocketBuffer)];
249 assert_eq!(nlas.as_slice().buffer_len(), 8);
250
251 let mut vec = vec![0xff; 8];
252 nlas.as_slice().emit(&mut vec);
253 assert_eq!(&vec[..], &ATTACHED[16..24]);
254
255 let nlas = vec![Xdp::Attached(XdpAttached::Hardware)];
257 assert_eq!(nlas.as_slice().buffer_len(), 8);
258
259 let mut vec = vec![0xff; 8];
260 nlas.as_slice().emit(&mut vec);
261 assert_eq!(&vec[..], &ATTACHED[24..32]);
262
263 let nlas = vec![Xdp::Attached(XdpAttached::Multiple)];
265 assert_eq!(nlas.as_slice().buffer_len(), 8);
266
267 let mut vec = vec![0xff; 8];
268 nlas.as_slice().emit(&mut vec);
269 assert_eq!(&vec[..], &ATTACHED[32..40]);
270
271 let nlas = vec![Xdp::Attached(XdpAttached::Other(252))];
273 assert_eq!(nlas.as_slice().buffer_len(), 8);
274
275 let mut vec = vec![0xff; 8];
276 nlas.as_slice().emit(&mut vec);
277 assert_eq!(&vec[..], &ATTACHED[40..48]);
278 }
279
280 #[rustfmt::skip]
281 static XDP: [u8; 72] = [
282 0x08, 0x00, 0x01, 0x00, 0xA0, 0x74, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xA1, 0x74, 0x00, 0x00, 0x08, 0x00, 0xfc, 0x00, 0xA1, 0x74, 0x00, 0x00, 0x06, 0x00, 0xfb, 0x00, 0xaa, 0xab, 0x00, 0x00, ];
311
312 #[test]
313 fn parse_xdp() {
314 let nla = NlaBuffer::new_checked(&XDP[..]).unwrap();
315 let parsed = VecXdp::parse(&nla).unwrap().0;
316 let expected = vec![
317 Xdp::Fd(29856),
318 Xdp::Flags(0),
319 Xdp::ProgId(103),
320 Xdp::DrvProgId(101),
321 Xdp::SkbProgId(101),
322 Xdp::HwProgId(101),
323 Xdp::ExpectedFd(29857),
324 Xdp::Other(
325 DefaultNla::parse(&NlaBuffer::new(&XDP[56..64])).unwrap(),
326 ),
327 Xdp::Other(DefaultNla::parse(&NlaBuffer::new(&XDP[64..])).unwrap()),
328 ];
329 assert_eq!(expected, parsed);
330 }
331
332 #[test]
333 fn emit_xdp() {
334 let nlas = vec![
335 Xdp::Fd(29856),
336 Xdp::Flags(0),
337 Xdp::ProgId(103),
338 Xdp::DrvProgId(101),
339 Xdp::SkbProgId(101),
340 Xdp::HwProgId(101),
341 Xdp::ExpectedFd(29857),
342 Xdp::Other(
343 DefaultNla::parse(&NlaBuffer::new(&XDP[56..64])).unwrap(),
344 ),
345 Xdp::Other(DefaultNla::parse(&NlaBuffer::new(&XDP[64..])).unwrap()),
346 ];
347 assert_eq!(nlas.as_slice().buffer_len(), XDP.len());
348
349 let mut vec = vec![0xff; XDP.len()];
350 nlas.as_slice().emit(&mut vec);
351 assert_eq!(&vec[..], &XDP[..]);
352 }
353}