Skip to content

Commit 75ce74c

Browse files
FallingSnowcathay4t
authored andcommitted
Add XDP nlas structure support
Currently and XDP nlas returns only a Vec<u8>. This commit adds an Xdp enum that breaks down an XDP nlas into attributes. A XdpAttached enum also provides definitions of xdp attachment types. Signed-off-by: Ayrton Sparling <[email protected]>
1 parent 4605b65 commit 75ce74c

File tree

3 files changed

+373
-8
lines changed

3 files changed

+373
-8
lines changed

src/rtnl/constants.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,16 +1172,21 @@ pub const RTNLGRP_IPV6_MROUTE_R: u32 = 31;
11721172
// pub const IFLA_OFFLOAD_XSTATS_UNSPEC: int = 0;
11731173
// pub const IFLA_OFFLOAD_XSTATS_CPU_HIT: int = 1;
11741174
//
1175-
// pub const XDP_ATTACHED_NONE: int = 0;
1176-
// pub const XDP_ATTACHED_DRV: int = 1;
1177-
// pub const XDP_ATTACHED_SKB: int = 2;
1178-
// pub const XDP_ATTACHED_HW: int = 3;
1175+
pub const XDP_ATTACHED_NONE: u8 = 0;
1176+
pub const XDP_ATTACHED_DRV: u8 = 1;
1177+
pub const XDP_ATTACHED_SKB: u8 = 2;
1178+
pub const XDP_ATTACHED_HW: u8 = 3;
1179+
pub const XDP_ATTACHED_MULTI: u8 = 4;
11791180

11801181
pub const IFLA_XDP_UNSPEC: u32 = 0;
11811182
pub const IFLA_XDP_FD: u32 = 1;
11821183
pub const IFLA_XDP_ATTACHED: u32 = 2;
11831184
pub const IFLA_XDP_FLAGS: u32 = 3;
11841185
pub const IFLA_XDP_PROG_ID: u32 = 4;
1186+
pub const IFLA_XDP_DRV_PROG_ID: u32 = 5;
1187+
pub const IFLA_XDP_SKB_PROG_ID: u32 = 6;
1188+
pub const IFLA_XDP_HW_PROG_ID: u32 = 7;
1189+
pub const IFLA_XDP_EXPECTED_FD: u32 = 8;
11851190

11861191
// pub const IFLA_EVENT_NONE: int = 0;
11871192
// pub const IFLA_EVENT_REBOOT: int = 1;

src/rtnl/link/nlas/link_xdp.rs

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use std::{convert::TryFrom, mem::size_of, os::fd::RawFd};
4+
5+
use anyhow::Context;
6+
use byteorder::{ByteOrder, NativeEndian};
7+
use netlink_packet_utils::{
8+
nla::{DefaultNla, Nla, NlaBuffer, NlasIterator},
9+
parsers::{parse_i32, parse_u32},
10+
DecodeError, Parseable,
11+
};
12+
13+
use crate::constants::*;
14+
15+
#[non_exhaustive]
16+
#[derive(Debug, PartialEq, Eq, Clone)]
17+
pub 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+
29+
impl 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+
78+
pub(crate) struct VecXdp(pub(crate) Vec<Xdp>);
79+
80+
// These NLAs are nested, meaning they are NLAs that contain NLAs. These NLAs
81+
// can contain more nested NLAs nla->type // IFLA_XDP
82+
// nla->len
83+
// nla->data[] // <- You are here == Vec<Xdp>
84+
// nla->data[0].type <- nla.kind()
85+
// nla->data[0].len
86+
impl<'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)]
137+
pub enum XdpAttached {
138+
/// XDP_ATTACHED_NONE
139+
None,
140+
/// XDP_ATTACHED_DRV
141+
Driver,
142+
/// XDP_ATTACHED_SKB
143+
SocketBuffer,
144+
/// XDP_ATTACHED_HW
145+
Hardware,
146+
/// XDP_ATTACHED_MULTI
147+
Multiple,
148+
/// This crate is unaware of the attachment type the kernel is reporting
149+
Other(u8),
150+
}
151+
152+
impl 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+
167+
impl 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)]
181+
mod tests {
182+
use netlink_packet_utils::Emitable;
183+
184+
use super::*;
185+
186+
#[rustfmt::skip]
187+
static ATTACHED: [u8; 48] = [
188+
0x05, 0x00, // length = 5
189+
0x02, 0x00, // type = 2 = IFLA_XDP_ATTACHED
190+
0x00, 0x00, // none = XDP_ATTACHED_NONE
191+
0x00, 0x00, // padding
192+
0x05, 0x00, // length = 5
193+
0x02, 0x00, // type = 2 = IFLA_XDP_ATTACHED
194+
0x01, 0x00, // driver = XDP_ATTACHED_DRV
195+
0x00, 0x00, // padding
196+
0x05, 0x00, // length = 5
197+
0x02, 0x00, // type = 2 = IFLA_XDP_ATTACHED
198+
0x02, 0x00, // skb = XDP_ATTACHED_SKB
199+
0x00, 0x00, // padding
200+
0x05, 0x00, // length = 5
201+
0x02, 0x00, // type = 2 = IFLA_XDP_ATTACHED
202+
0x03, 0x00, // hw = XDP_ATTACHED_HW
203+
0x00, 0x00, // padding
204+
0x05, 0x00, // length = 5
205+
0x02, 0x00, // type = 2 = IFLA_XDP_ATTACHED
206+
0x04, 0x00, // multi = XDP_ATTACHED_MULTI
207+
0x00, 0x00, // padding
208+
0x05, 0x00, // length = 5
209+
0x02, 0x00, // type = 2 = IFLA_XDP_ATTACHED
210+
0xfc, 0x00, // other = random number = 252
211+
0x00, 0x00, // padding
212+
];
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+
// None
232+
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+
// Driver
240+
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+
// SocketBuffer/skb
248+
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+
// Hardware
256+
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+
// Multiple
264+
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+
// Multiple
272+
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, // length = 8
283+
0x01, 0x00, // type = 1 = IFLA_XDP_FD
284+
0xA0, 0x74, 0x00, 0x00, // 29856
285+
0x08, 0x00, // length = 8
286+
0x03, 0x00, // type = 3 = IFLA_XDP_FLAGS
287+
0x00, 0x00, 0x00, 0x00, // empty
288+
0x08, 0x00, // length = 8
289+
0x04, 0x00, // type = 4 = IFLA_XDP_PROG_ID
290+
0x67, 0x00, 0x00, 0x00, // 103
291+
0x08, 0x00, // length = 8
292+
0x05, 0x00, // type = 5 = IFLA_XDP_DRV_PROG_ID
293+
0x65, 0x00, 0x00, 0x00, // 101
294+
0x08, 0x00, // length = 8
295+
0x06, 0x00, // type = 6 = IFLA_XDP_DRV_SKB_ID
296+
0x65, 0x00, 0x00, 0x00, // 101
297+
0x08, 0x00, // length = 8
298+
0x07, 0x00, // type = 7 = IFLA_XDP_DRV_HW_ID
299+
0x65, 0x00, 0x00, 0x00, // 101
300+
0x08, 0x00, // length = 8
301+
0x08, 0x00, // type = 8 = IFLA_XDP_DRV_EXPECTED_FD
302+
0xA1, 0x74, 0x00, 0x00, // 29857
303+
0x08, 0x00, // length = 8
304+
0xfc, 0x00, // type = 252 = random number/unknown type
305+
0xA1, 0x74, 0x00, 0x00, // 29857
306+
0x06, 0x00, // length = 6
307+
0xfb, 0x00, // type = 251 = random number/unknown type
308+
0xaa, 0xab, // 29857
309+
0x00, 0x00, // padding
310+
];
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+
}

0 commit comments

Comments
 (0)