Skip to content

Commit 930eca9

Browse files
committed
[net] Introduce abstractions for the New API (NAPI)
This patch introduces the necessary abstractions to declare, attach, and schedule (as well as prepare the scheduling of) NAPI structures. The NAPI mechanism is necessary to write network device drivers, especially because they help handle passing socket buffers to the Generic Receiver Offload (GRO) mechanism. Rust drivers can implement the `net::gro::NapiPoller` trait over a type which implements their polling function. Afterwards, a NAPI can be tied to a device with the polling function by calling `net::Device::napi_add` with a type argument implementing the corresponding `NapiPoller` trait, as well as a regular argument giving a reference to the NAPI structure used by the network driver. Signed-off-by: Amélie Gonzalez <[email protected]>
1 parent c8d1ae2 commit 930eca9

File tree

4 files changed

+297
-0
lines changed

4 files changed

+297
-0
lines changed

rust/bindings/bindings_helper.h

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/irq.h>
2323
#include <linux/miscdevice.h>
2424
#include <linux/module.h>
25+
#include <linux/netdevice.h>
2526
#include <linux/netfilter_arp.h>
2627
#include <linux/netfilter.h>
2728
#include <linux/netfilter_ipv4.h>
@@ -36,6 +37,7 @@
3637
#include <linux/sysctl.h>
3738
#include <linux/uaccess.h>
3839
#include <linux/uio.h>
40+
#include <net/gro.h>
3941

4042
/* `bindgen` gets confused at certain things. */
4143
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

rust/helpers.c

+15
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,28 @@
4040
#include <linux/skbuff.h>
4141
#include <linux/uaccess.h>
4242
#include <linux/uio.h>
43+
#include <net/gro.h>
4344

4445
__noreturn void rust_helper_BUG(void)
4546
{
4647
BUG();
4748
}
4849
EXPORT_SYMBOL_GPL(rust_helper_BUG);
4950

51+
#ifdef CONFIG_NET
52+
void rust_helper_napi_schedule(struct napi_struct* napi)
53+
{
54+
napi_schedule(napi);
55+
}
56+
EXPORT_SYMBOL_GPL(rust_helper_napi_schedule);
57+
58+
void rust_helper_netif_napi_add(struct net_device* net, struct napi_struct* napi, int (*poll)(struct napi_struct* napi, int budget))
59+
{
60+
netif_napi_add(net, napi, poll);
61+
}
62+
EXPORT_SYMBOL_GPL(rust_helper_netif_napi_add);
63+
#endif // CONFIG_NET
64+
5065
void rust_helper_clk_disable_unprepare(struct clk *clk)
5166
{
5267
return clk_disable_unprepare(clk);

rust/kernel/net.rs

+27
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use core::{cell::UnsafeCell, ptr::NonNull};
1111

1212
#[cfg(CONFIG_NETFILTER)]
1313
pub mod filter;
14+
pub mod gro;
1415

1516
/// Wraps the kernel's `struct net_device`.
1617
#[repr(transparent)]
@@ -29,6 +30,32 @@ unsafe impl AlwaysRefCounted for Device {
2930
}
3031
}
3132

33+
impl Device {
34+
/// # Safety
35+
///
36+
/// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
37+
/// instance of [`Device`] returned
38+
pub(crate) unsafe fn from_ptr<'a>(ptr: *mut bindings::net_device) -> &'a Device {
39+
// SAFETY: The safety requirements guarantee the validity of the pointer, and since
40+
// `Device` is transparent, the cast is OK
41+
unsafe { &*ptr.cast() }
42+
}
43+
44+
/// Add a New API (NAPI) poller to the device
45+
///
46+
/// This must be done prior to the registration of said device.
47+
pub fn napi_add<POLLER: gro::NapiPoller>(&mut self, napi: &mut gro::Napi) {
48+
// Get all of the necessary pointers
49+
let dev_ptr = self.0.get();
50+
// The cast is valid because `Napi` is transparent
51+
let napi_ptr: *mut bindings::napi_struct = (napi as *mut gro::Napi).cast();
52+
let poll_func = gro::PollerBuilder::<POLLER>::build_function();
53+
54+
// SAFETY: C call with parameters that are all known to be non-null and valid
55+
unsafe { bindings::netif_napi_add(dev_ptr, napi_ptr, poll_func) };
56+
}
57+
}
58+
3259
/// Wraps the kernel's `struct net`.
3360
#[repr(transparent)]
3461
pub struct Namespace(UnsafeCell<bindings::net>);

rust/kernel/net/gro.rs

+253
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
//! Module for the Generic Receiver Offload
2+
//!
3+
//! C headers: [`include/net/gro.h`](../../../include/net/gro.h),
4+
5+
use crate::{
6+
bindings,
7+
net::{Device, SkBuff},
8+
};
9+
use core::marker::PhantomData;
10+
use macros::vtable;
11+
12+
/// Abstraction around the kernel's `struct napi_struct`
13+
///
14+
/// For additional documentation about how New API (NAPI) works, consult the
15+
/// [`Linux Foundation Wiki`](https://wiki.linuxfoundation.org/networking/napi).
16+
#[repr(transparent)]
17+
#[derive(Default, Clone, Copy)]
18+
pub struct Napi(bindings::napi_struct);
19+
20+
/// A trait to implement NAPI Polling Functions
21+
#[vtable]
22+
pub trait NapiPoller {
23+
/// Polling function
24+
///
25+
/// The NAPI structure is given mutably. The network driver should do its
26+
/// best to receive packets from the interface, and attempt to retrieve at
27+
/// most `budget` packets, returning the exact number it extracted.
28+
fn poll(_napi: &mut Napi, _budget: i32) -> i32 {
29+
// Budget is made into an `i32` because nothing in the kernel forbids
30+
// drivers from an explicit call to napi_poll(), and their polling
31+
// functions could return negative values for reasons only they know of.
32+
0
33+
}
34+
}
35+
36+
/// Building structure for poller functions
37+
pub struct PollerBuilder<T: NapiPoller> {
38+
_p: PhantomData<T>,
39+
}
40+
41+
type PollerFunction = unsafe extern "C" fn(*mut bindings::napi_struct, i32) -> i32;
42+
43+
impl<T: NapiPoller> PollerBuilder<T> {
44+
const FUNC: Option<PollerFunction> = Some(Self::poller_callback);
45+
46+
/// Build the poller function pointer associated with the generics' callback
47+
pub const fn build_function() -> Option<PollerFunction> {
48+
Self::FUNC
49+
}
50+
51+
unsafe extern "C" fn poller_callback(napi: *mut bindings::napi_struct, budget: i32) -> i32 {
52+
// Try and build the napi from this pointer
53+
// SAFETY: The kernel will necessarily give us a non-null and valid
54+
// pointer, so we can dereference it, and use it while satisfying the
55+
// invariants of `Napi`. Furthermore, the cast is valid because `Napi`
56+
// is transparent.
57+
let napi: &mut Napi = unsafe { &mut *napi.cast() };
58+
59+
// The rest is primitive, hence, trivial
60+
<T>::poll(napi, budget)
61+
}
62+
}
63+
64+
impl Napi {
65+
/// Create a new, empty, NAPI
66+
pub fn new() -> Self {
67+
Self(bindings::napi_struct::default())
68+
}
69+
70+
/// Obtain the inner pointer cast to the bindings type
71+
fn get_inner_cast(&mut self) -> *mut bindings::napi_struct {
72+
(self as *mut Self).cast()
73+
}
74+
75+
/// Set a bit in the state bitmap of the [`Napi`] to 1
76+
pub fn set_state_bit(&mut self, bit: NapiState) {
77+
let bit_as = u64::from(bit as u32);
78+
79+
self.0.state |= 1 << bit_as;
80+
}
81+
82+
/// Enable the NAPI
83+
///
84+
/// You must always set a state using [`Self::set_state_bit`] prior to
85+
/// calling this method.
86+
pub fn enable(&mut self) {
87+
let napi_ptr: *mut Napi = self;
88+
89+
// SAFETY: The cast is valid because `Napi` is transparent to that type,
90+
// and the call is sound because the pointer is guaranteed to be
91+
// non-null and valid all throughout the lifetime of the call.
92+
unsafe { bindings::napi_enable(napi_ptr.cast()) };
93+
}
94+
95+
/// Disable the NAPI
96+
pub fn disable(&mut self) {
97+
let napi_ptr: *mut Napi = self;
98+
99+
// SAFETY: The cast is valid because `Napi` is transparent to that type,
100+
// and the call is sound because the pointer is guaranteed to be
101+
// non-null and valid all throughout the lifetime of the call.
102+
unsafe { bindings::napi_disable(napi_ptr.cast()) };
103+
}
104+
105+
/// Schedule the NAPI to run on this CPU
106+
///
107+
/// This is equivalent to calling [`Self::prepare_scheduling`] followed by
108+
/// [`Self::actually_schedule`] one after the other.
109+
pub fn schedule(&mut self) {
110+
// SAFETY: The call is safe because the pointer is guaranteed to be
111+
// non-null and valid all throughout the call.
112+
unsafe { bindings::napi_schedule(self.get_inner_cast()) };
113+
}
114+
115+
/// Prepare the scheduling of the NAPI
116+
///
117+
/// If the NAPI is already due to be scheduled on this CPU, do nothing
118+
/// and return `false`.
119+
///
120+
/// Call [`Self::actually_schedule`] if this method returns `true`.
121+
pub fn prepare_scheduling(&mut self) -> bool {
122+
// SAFETY: The call is safe because the pointer is guaranteed to be
123+
// non-null and valid all throughout the call.
124+
unsafe { bindings::napi_schedule_prep(self.get_inner_cast()) }
125+
}
126+
127+
/// Actually schedule the NAPI after preparation
128+
///
129+
/// Call [`Self::prepare_scheduling`] prior to calling this method.
130+
pub fn actually_schedule(&mut self) {
131+
// SAFETY: The call is safe because the pointer is guaranteed to be
132+
// non-null and valid all throughout the call.
133+
unsafe { bindings::__napi_schedule(self.get_inner_cast()) };
134+
}
135+
136+
/// Complete after no packets received by the NAPI
137+
///
138+
/// This is equivalent to calling [`Self::complete_done`] with a work of 0.
139+
pub fn complete(&mut self) -> bool {
140+
// SAFETY: The call is safe because the pointer is guaranteed to be
141+
// non-null and valid all throughout the call
142+
unsafe { bindings::napi_complete_done(self.get_inner_cast(), 0) }
143+
}
144+
145+
/// Complete with a given number of packets received by the NAPI
146+
pub fn complete_done(&mut self, work: i32) -> bool {
147+
// SAFETY: The call is safe because `work` is primitive, and the pointer
148+
// is guaranteed to be non-null and valid throughout the call's
149+
// lifetime.
150+
unsafe { bindings::napi_complete_done(self.get_inner_cast(), work) }
151+
}
152+
153+
/// Return a reference to the device that the NAPI is currently on, if any
154+
pub fn get_device(&self) -> Option<&Device> {
155+
let dev_ptr = self.0.dev;
156+
if dev_ptr.is_null() {
157+
None
158+
} else {
159+
// SAFETY: We've guaranteed that `dev_ptr` is non-null. The kernel
160+
// guarantees that it's a pointer to a net_device, and it will stay
161+
// valid for the duration of the instance given here.
162+
Some(unsafe { Device::from_ptr(dev_ptr) })
163+
}
164+
}
165+
166+
/// Transmit to the GRO
167+
pub fn gro_receive(&mut self, sk_buff: &mut SkBuff) -> GroResult {
168+
let self_ptr = self.get_inner_cast();
169+
let skb_ptr: *mut bindings::sk_buff = (sk_buff as *mut SkBuff).cast();
170+
171+
// SAFETY: The invariants of SkBuff and ourself guarantees that we can
172+
// use these pointers.
173+
let res = unsafe { bindings::napi_gro_receive(self_ptr, skb_ptr) };
174+
res.try_into()
175+
.expect("Unable to convert return of napi_gro_receive to gro_result\n")
176+
}
177+
}
178+
179+
/// Enumerator for the return type of [`SkBuff::gro_receive`]
180+
#[repr(u32)]
181+
#[derive(Debug, Clone, Copy)]
182+
pub enum GroResult {
183+
/// Merged but not freed
184+
Merged = bindings::gro_result_GRO_MERGED,
185+
186+
/// Merged and freed
187+
MergedFree = bindings::gro_result_GRO_MERGED_FREE,
188+
189+
/// Held
190+
Held = bindings::gro_result_GRO_HELD,
191+
192+
/// Normal
193+
Normal = bindings::gro_result_GRO_NORMAL,
194+
195+
/// Consumed
196+
Consumed = bindings::gro_result_GRO_CONSUMED,
197+
}
198+
199+
impl TryFrom<u32> for GroResult {
200+
type Error = ();
201+
fn try_from(u: u32) -> core::result::Result<Self, Self::Error> {
202+
match u {
203+
bindings::gro_result_GRO_MERGED => Ok(Self::Merged),
204+
bindings::gro_result_GRO_MERGED_FREE => Ok(Self::MergedFree),
205+
bindings::gro_result_GRO_HELD => Ok(Self::Held),
206+
bindings::gro_result_GRO_NORMAL => Ok(Self::Normal),
207+
bindings::gro_result_GRO_CONSUMED => Ok(Self::Consumed),
208+
_ => Err(()),
209+
}
210+
}
211+
}
212+
213+
/// Enumerator for the state of a [`Napi`]
214+
///
215+
/// The state of a [`Napi`] must always be set prior to enabling it.
216+
#[repr(u32)]
217+
pub enum NapiState {
218+
/// Poll is scheduled
219+
Sched = bindings::NAPI_STATE_SCHED,
220+
221+
/// Rescheduling
222+
Missed = bindings::NAPI_STATE_MISSED,
223+
224+
/// Disable is pending
225+
Disable = bindings::NAPI_STATE_DISABLE,
226+
227+
/// Netpoll - don't dequeue from poll_list
228+
Npsvc = bindings::NAPI_STATE_NPSVC,
229+
230+
/// NAPI added to system list
231+
Listed = bindings::NAPI_STATE_LISTED,
232+
233+
/// Do not add in napi_hash, no busy polling
234+
NoBusyPoll = bindings::NAPI_STATE_NO_BUSY_POLL,
235+
236+
/// `sk_busy_loop()` owns this NAPI
237+
InBusyPoll = bindings::NAPI_STATE_IN_BUSY_POLL,
238+
239+
/// Prefer busy-polling over softirqd processing
240+
PreferBusyPoll = bindings::NAPI_STATE_PREFER_BUSY_POLL,
241+
242+
/// The poll is performed inside its own thread
243+
Threaded = bindings::NAPI_STATE_THREADED,
244+
245+
/// NAPI is currently scheduled in threaded mode
246+
SchedThreaded = bindings::NAPI_STATE_SCHED_THREADED,
247+
}
248+
249+
impl From<NapiState> for u32 {
250+
fn from(n: NapiState) -> u32 {
251+
n as u32
252+
}
253+
}

0 commit comments

Comments
 (0)