netlink_packet_route/link/
xdp.rs

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