netlink_packet_route/link/
xdp.rs

1// SPDX-License-Identifier: MIT
2
3use std::convert::TryFrom;
4use std::mem::size_of;
5use std::os::fd::RawFd;
6
7use anyhow::Context;
8use byteorder::{ByteOrder, NativeEndian};
9use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
10use netlink_packet_utils::parsers::{parse_i32, parse_u32, parse_u8};
11use netlink_packet_utils::{DecodeError, Parseable};
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) => NativeEndian::write_u32(buffer, *value),
64            Self::SkbProgId(ref value) => NativeEndian::write_u32(buffer, *value),
65            Self::HwProgId(ref value) => NativeEndian::write_u32(buffer, *value),
66            Self::ExpectedFd(ref value) => NativeEndian::write_u32(buffer, *value),
67            Self::Other(ref nla) => nla.emit_value(buffer),
68        }
69    }
70
71    fn kind(&self) -> u16 {
72        match self {
73            Self::Fd(_) => IFLA_XDP_FD as u16,
74            Self::Attached(_) => IFLA_XDP_ATTACHED as u16,
75            Self::Flags(_) => IFLA_XDP_FLAGS as u16,
76            Self::ProgId(_) => IFLA_XDP_PROG_ID as u16,
77            Self::DrvProgId(_) => IFLA_XDP_DRV_PROG_ID as u16,
78            Self::SkbProgId(_) => IFLA_XDP_SKB_PROG_ID as u16,
79            Self::HwProgId(_) => IFLA_XDP_HW_PROG_ID as u16,
80            Self::ExpectedFd(_) => IFLA_XDP_EXPECTED_FD as u16,
81            Self::Other(nla) => nla.kind(),
82        }
83    }
84}
85
86impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for LinkXdp {
87    type Error = DecodeError;
88    fn parse(nla: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
89        let payload = nla.value();
90        Ok(match nla.kind() as u32 {
91            IFLA_XDP_FD => Self::Fd(parse_i32(payload).context("invalid IFLA_XDP_FD value")?),
92            IFLA_XDP_ATTACHED => {
93                let err = "invalid IFLA_XDP_ATTACHED value";
94                let value = parse_u8(payload).context(err)?;
95                Self::Attached(XdpAttached::try_from(value).context(err)?)
96            }
97            IFLA_XDP_FLAGS => {
98                Self::Flags(parse_u32(payload).context("invalid IFLA_XDP_FLAGS value")?)
99            }
100            IFLA_XDP_PROG_ID => {
101                Self::ProgId(parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?)
102            }
103            IFLA_XDP_DRV_PROG_ID => {
104                Self::DrvProgId(parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?)
105            }
106            IFLA_XDP_SKB_PROG_ID => {
107                Self::SkbProgId(parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?)
108            }
109            IFLA_XDP_HW_PROG_ID => {
110                Self::HwProgId(parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?)
111            }
112            IFLA_XDP_EXPECTED_FD => {
113                Self::ExpectedFd(parse_u32(payload).context("invalid IFLA_XDP_PROG_ID value")?)
114            }
115            _ => Self::Other(
116                DefaultNla::parse(nla).context(format!("unknown NLA type {}", nla.kind()))?,
117            ),
118        })
119    }
120}
121
122pub(crate) struct VecLinkXdp(pub(crate) Vec<LinkXdp>);
123
124// These NLAs are nested, meaning they are NLAs that contain NLAs. These NLAs
125// can contain more nested NLAs nla->type     // IFLA_XDP
126// nla->len
127// nla->data[]   // <- You are here == Vec<Xdp>
128//  nla->data[0].type   <- nla.kind()
129//  nla->data[0].len
130impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecLinkXdp {
131    type Error = DecodeError;
132    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
133        let mut res = Vec::new();
134        let nlas = NlasIterator::new(buf.into_inner());
135        for nla in nlas {
136            let nla = nla?;
137            res.push(LinkXdp::parse(&nla)?);
138        }
139        Ok(VecLinkXdp(res))
140    }
141}
142
143#[derive(Debug, PartialEq, Eq, Clone, Copy)]
144#[non_exhaustive]
145pub enum XdpAttached {
146    /// XDP_ATTACHED_NONE
147    None,
148    /// XDP_ATTACHED_DRV
149    Driver,
150    /// XDP_ATTACHED_SKB
151    SocketBuffer,
152    /// XDP_ATTACHED_HW
153    Hardware,
154    /// XDP_ATTACHED_MULTI
155    Multiple,
156    /// This crate is unaware of the attachment type the kernel is reporting
157    Other(u8),
158}
159
160impl TryFrom<u8> for XdpAttached {
161    type Error = DecodeError;
162
163    fn try_from(value: u8) -> Result<Self, Self::Error> {
164        match value {
165            XDP_ATTACHED_NONE => Ok(XdpAttached::None),
166            XDP_ATTACHED_DRV => Ok(XdpAttached::Driver),
167            XDP_ATTACHED_SKB => Ok(XdpAttached::SocketBuffer),
168            XDP_ATTACHED_HW => Ok(XdpAttached::Hardware),
169            XDP_ATTACHED_MULTI => Ok(XdpAttached::Multiple),
170            _ => Ok(XdpAttached::Other(value)),
171        }
172    }
173}
174
175impl XdpAttached {
176    fn as_u8(&self) -> u8 {
177        match self {
178            XdpAttached::None => XDP_ATTACHED_NONE,
179            XdpAttached::Driver => XDP_ATTACHED_DRV,
180            XdpAttached::SocketBuffer => XDP_ATTACHED_SKB,
181            XdpAttached::Hardware => XDP_ATTACHED_HW,
182            XdpAttached::Multiple => XDP_ATTACHED_MULTI,
183            XdpAttached::Other(other) => *other,
184        }
185    }
186}