netlink_packet_route/link/
xdp.rs1use std::{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, parse_u8},
10 DecodeError, Parseable,
11};
12
13const IFLA_XDP_FD: u32 = 1;
14const IFLA_XDP_ATTACHED: u32 = 2;
15const IFLA_XDP_FLAGS: u32 = 3;
16const IFLA_XDP_PROG_ID: u32 = 4;
17const IFLA_XDP_DRV_PROG_ID: u32 = 5;
18const IFLA_XDP_SKB_PROG_ID: u32 = 6;
19const IFLA_XDP_HW_PROG_ID: u32 = 7;
20const IFLA_XDP_EXPECTED_FD: u32 = 8;
21
22const XDP_ATTACHED_NONE: u8 = 0;
23const XDP_ATTACHED_DRV: u8 = 1;
24const XDP_ATTACHED_SKB: u8 = 2;
25const XDP_ATTACHED_HW: u8 = 3;
26const XDP_ATTACHED_MULTI: u8 = 4;
27
28#[non_exhaustive]
29#[derive(Debug, PartialEq, Eq, Clone)]
30pub enum LinkXdp {
31 Fd(RawFd),
32 Attached(XdpAttached),
33 Flags(u32),
34 ProgId(u32),
35 DrvProgId(u32),
36 SkbProgId(u32),
37 HwProgId(u32),
38 ExpectedFd(u32),
39 Other(DefaultNla),
40}
41
42impl Nla for LinkXdp {
43 fn value_len(&self) -> usize {
44 match self {
45 Self::Fd(_) => size_of::<RawFd>(),
46 Self::Attached(_) => size_of::<u8>(),
47 Self::Flags(_) => size_of::<u32>(),
48 Self::ProgId(_) => size_of::<u32>(),
49 Self::DrvProgId(_) => size_of::<u32>(),
50 Self::SkbProgId(_) => size_of::<u32>(),
51 Self::HwProgId(_) => size_of::<u32>(),
52 Self::ExpectedFd(_) => size_of::<u32>(),
53 Self::Other(nla) => nla.value_len(),
54 }
55 }
56
57 fn emit_value(&self, buffer: &mut [u8]) {
58 match self {
59 Self::Fd(ref value) => NativeEndian::write_i32(buffer, *value),
60 Self::Attached(ref value) => buffer[0] = value.as_u8(),
61 Self::Flags(ref value) => NativeEndian::write_u32(buffer, *value),
62 Self::ProgId(ref value) => NativeEndian::write_u32(buffer, *value),
63 Self::DrvProgId(ref value) => {
64 NativeEndian::write_u32(buffer, *value)
65 }
66 Self::SkbProgId(ref value) => {
67 NativeEndian::write_u32(buffer, *value)
68 }
69 Self::HwProgId(ref value) => {
70 NativeEndian::write_u32(buffer, *value)
71 }
72 Self::ExpectedFd(ref value) => {
73 NativeEndian::write_u32(buffer, *value)
74 }
75 Self::Other(ref nla) => nla.emit_value(buffer),
76 }
77 }
78
79 fn kind(&self) -> u16 {
80 match self {
81 Self::Fd(_) => IFLA_XDP_FD as u16,
82 Self::Attached(_) => IFLA_XDP_ATTACHED as u16,
83 Self::Flags(_) => IFLA_XDP_FLAGS as u16,
84 Self::ProgId(_) => IFLA_XDP_PROG_ID as u16,
85 Self::DrvProgId(_) => IFLA_XDP_DRV_PROG_ID as u16,
86 Self::SkbProgId(_) => IFLA_XDP_SKB_PROG_ID as u16,
87 Self::HwProgId(_) => IFLA_XDP_HW_PROG_ID as u16,
88 Self::ExpectedFd(_) => IFLA_XDP_EXPECTED_FD as u16,
89 Self::Other(nla) => nla.kind(),
90 }
91 }
92}
93
94impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for LinkXdp {
95 fn parse(nla: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
96 let payload = nla.value();
97 Ok(match nla.kind() as u32 {
98 IFLA_XDP_FD => Self::Fd(
99 parse_i32(payload).context("invalid IFLA_XDP_FD value")?,
100 ),
101 IFLA_XDP_ATTACHED => {
102 let err = "invalid IFLA_XDP_ATTACHED value";
103 let value = parse_u8(payload).context(err)?;
104 Self::Attached(XdpAttached::try_from(value).context(err)?)
105 }
106 IFLA_XDP_FLAGS => Self::Flags(
107 parse_u32(payload).context("invalid IFLA_XDP_FLAGS value")?,
108 ),
109 IFLA_XDP_PROG_ID => Self::ProgId(
110 parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?,
111 ),
112 IFLA_XDP_DRV_PROG_ID => Self::DrvProgId(
113 parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?,
114 ),
115 IFLA_XDP_SKB_PROG_ID => Self::SkbProgId(
116 parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?,
117 ),
118 IFLA_XDP_HW_PROG_ID => Self::HwProgId(
119 parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?,
120 ),
121 IFLA_XDP_EXPECTED_FD => Self::ExpectedFd(
122 parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?,
123 ),
124 _ => Self::Other(
125 DefaultNla::parse(nla)
126 .context(format!("unknown NLA type {}", nla.kind()))?,
127 ),
128 })
129 }
130}
131
132pub(crate) struct VecLinkXdp(pub(crate) Vec<LinkXdp>);
133
134impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecLinkXdp {
141 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
142 let mut res = Vec::new();
143 let nlas = NlasIterator::new(buf.into_inner());
144 for nla in nlas {
145 let nla = nla?;
146 res.push(LinkXdp::parse(&nla)?);
147 }
148 Ok(VecLinkXdp(res))
149 }
150}
151
152#[derive(Debug, PartialEq, Eq, Clone, Copy)]
153#[non_exhaustive]
154pub enum XdpAttached {
155 None,
157 Driver,
159 SocketBuffer,
161 Hardware,
163 Multiple,
165 Other(u8),
167}
168
169impl TryFrom<u8> for XdpAttached {
170 type Error = DecodeError;
171
172 fn try_from(value: u8) -> Result<Self, Self::Error> {
173 match value {
174 XDP_ATTACHED_NONE => Ok(XdpAttached::None),
175 XDP_ATTACHED_DRV => Ok(XdpAttached::Driver),
176 XDP_ATTACHED_SKB => Ok(XdpAttached::SocketBuffer),
177 XDP_ATTACHED_HW => Ok(XdpAttached::Hardware),
178 XDP_ATTACHED_MULTI => Ok(XdpAttached::Multiple),
179 _ => Ok(XdpAttached::Other(value)),
180 }
181 }
182}
183
184impl XdpAttached {
185 fn as_u8(&self) -> u8 {
186 match self {
187 XdpAttached::None => XDP_ATTACHED_NONE,
188 XdpAttached::Driver => XDP_ATTACHED_DRV,
189 XdpAttached::SocketBuffer => XDP_ATTACHED_SKB,
190 XdpAttached::Hardware => XDP_ATTACHED_HW,
191 XdpAttached::Multiple => XDP_ATTACHED_MULTI,
192 XdpAttached::Other(other) => *other,
193 }
194 }
195}