Skip to content

Commit 06db922

Browse files
committed
rust: clean up net_device_ops
use from_kernel_result!. Also added SAFETY comments. Signed-off-by: FUJITA Tomonori <[email protected]>
1 parent 331c0bf commit 06db922

File tree

2 files changed

+72
-23
lines changed

2 files changed

+72
-23
lines changed

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/miscdevice.h>
2424
#include <linux/mm.h>
2525
#include <linux/module.h>
26+
#include <linux/netdevice.h>
2627
#include <linux/netfilter_arp.h>
2728
#include <linux/netfilter.h>
2829
#include <linux/netfilter_ipv4.h>

rust/kernel/net.rs

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
//! [`include/linux/skbuff.h`](../../../../include/linux/skbuff.h).
88
99
use crate::{
10-
bindings, device, error::code::ENOMEM, str::CStr, to_result, types::PointerWrapper, ARef,
11-
AlwaysRefCounted, Error, Result,
10+
bindings, device,
11+
error::{code::ENOMEM, from_kernel_result},
12+
str::CStr,
13+
to_result,
14+
types::PointerWrapper,
15+
ARef, AlwaysRefCounted, Error, Result,
1216
};
1317
use core::{
1418
cell::UnsafeCell,
@@ -50,67 +54,80 @@ impl Device {
5054

5155
/// Sets carrier.
5256
pub fn netif_carrier_on(&self) {
57+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
5358
unsafe { bindings::netif_carrier_on(self.0.get()) }
5459
}
5560

5661
/// Clears carrier.
5762
pub fn netif_carrier_off(&self) {
63+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
5864
unsafe { bindings::netif_carrier_off(self.0.get()) }
5965
}
6066

6167
/// Assigns Ethernet address to a net_device.
6268
pub fn eth_hw_addr_set(&self, addr: &[u8; 6]) {
69+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
6370
unsafe { bindings::eth_hw_addr_set(self.0.get(), addr as _) }
6471
}
6572

6673
/// Returns the mtu of the device.
6774
pub fn mtu_get(&self) -> u32 {
75+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
6876
unsafe { addr_of!((*self.0.get()).mtu).read() }
6977
}
7078

7179
/// Sets the max mtu of the device.
7280
pub fn max_mtu_set(&self, max_mtu: u32) {
81+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
7382
unsafe { addr_of_mut!((*self.0.get()).max_mtu).write(max_mtu) };
7483
}
7584

7685
/// Sets the minimum mtu of the device.
7786
pub fn min_mtu_set(&self, min_mtu: u32) {
87+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
7888
unsafe { addr_of_mut!((*self.0.get()).min_mtu).write(min_mtu) };
7989
}
8090

8191
/// Returns the flags of the device.
8292
pub fn flags_get(&self) -> u32 {
93+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
8394
unsafe { addr_of!((*self.0.get()).flags).read() }
8495
}
8596

8697
/// Sets the priv_flags of the device.
8798
pub fn priv_flags_get(&self) -> u64 {
99+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
88100
unsafe { addr_of!((*self.0.get()).priv_flags).read() }
89101
}
90102

91103
/// Returns the priv_flags of the device.
92104
pub fn priv_flags_set(&self, flags: u64) {
105+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
93106
unsafe { addr_of_mut!((*self.0.get()).priv_flags).write(flags) }
94107
}
95108

96109
/// Reports the number of bytes queued to hardware.
97110
pub fn sent_queue(&self, bytes: u32) {
111+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
98112
unsafe { bindings::netdev_sent_queue(self.0.get(), bytes) }
99113
}
100114

101115
/// Allows the upper layers to transmit.
102116
pub fn netif_start_queue(&self) {
117+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
103118
unsafe { bindings::netif_start_queue(self.0.get()) }
104119
}
105120

106121
/// Stop the upper layers to transmit.
107122
pub fn netif_stop_queue(&self) {
123+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
108124
unsafe { bindings::netif_stop_queue(self.0.get()) }
109125
}
110126

111127
/// Allocate an skbuff for rx on the device.
112128
/// with IP header placed at an aligned offset.
113129
pub fn alloc_skb_ip_align(&self, length: u32) -> Result<ARef<SkBuff>> {
130+
// SAFETY: The netdev is valid because the shared reference guarantees a nonzero refcount.
114131
let skb = unsafe { bindings::netdev_alloc_skb_ip_align(self.0.get(), length) };
115132
if skb.is_null() {
116133
Err(ENOMEM)
@@ -130,10 +147,12 @@ pub struct Registration<T: DeviceOperations> {
130147
impl<T: DeviceOperations> Registration<T> {
131148
/// Creates new instance of registration.
132149
pub fn try_new(parent: &dyn device::RawDevice) -> Result<Self> {
150+
// SAFETY: FFI call.
133151
let dev = unsafe { bindings::alloc_etherdev_mqs(0, 1, 1) };
134152
if dev.is_null() {
135153
Err(ENOMEM)
136154
} else {
155+
// SAFETY: `dev` was allocated during initialization and is guaranteed to be valid.
137156
unsafe { (*dev).dev.parent = parent.raw_device() }
138157
Ok(Registration {
139158
dev,
@@ -151,13 +170,20 @@ impl<T: DeviceOperations> Registration<T> {
151170

152171
/// Register a network device.
153172
pub fn register(&mut self, data: T::Data) -> Result {
154-
unsafe { (*self.dev).netdev_ops = Self::build_device_ops() }
155-
let ret = unsafe { bindings::register_netdev(self.dev) };
173+
// SAFETY: `dev` was allocated during initialization and is guaranteed to be valid.
174+
let ret = unsafe {
175+
(*self.dev).netdev_ops = Self::build_device_ops();
176+
bindings::register_netdev(self.dev)
177+
};
156178
if ret != 0 {
157179
Err(Error::from_kernel_errno(ret))
158180
} else {
159181
self.registered = true;
160182
unsafe {
183+
// SAFETY: The C contract guarantees that `data` is available
184+
// for implementers of the net_device operations (no other C code accesses
185+
// it), so we know that there are no concurrent threads/CPUs accessing
186+
// it (it's not visible to any other Rust code).
161187
bindings::dev_set_drvdata(&mut (*self.dev).dev, data.into_pointer() as _);
162188
}
163189
Ok(())
@@ -167,10 +193,13 @@ impl<T: DeviceOperations> Registration<T> {
167193

168194
impl<T: DeviceOperations> Drop for Registration<T> {
169195
fn drop(&mut self) {
170-
if self.registered {
171-
unsafe { bindings::unregister_netdev(self.dev) }
196+
// SAFETY: `dev` was allocated during initialization and guaranteed to be valid.
197+
unsafe {
198+
if self.registered {
199+
bindings::unregister_netdev(self.dev);
200+
}
201+
bindings::free_netdev(self.dev);
172202
}
173-
unsafe { bindings::free_netdev(self.dev) }
174203
}
175204
}
176205

@@ -287,36 +316,55 @@ impl<T: DeviceOperations> Registration<T> {
287316
ndo_get_tstamp: None,
288317
};
289318

290-
const unsafe fn build_device_ops() -> &'static bindings::net_device_ops {
319+
const fn build_device_ops() -> &'static bindings::net_device_ops {
291320
&Self::DEVICE_OPS
292321
}
293322

294323
unsafe extern "C" fn open_callback(netdev: *mut bindings::net_device) -> core::ffi::c_int {
295-
let ptr = unsafe { bindings::dev_get_drvdata(&mut (*netdev).dev) };
296-
let dev = unsafe { Device::from_ptr(netdev) };
297-
let data = unsafe { T::Data::borrow(ptr) };
298-
T::open(dev, data)
324+
from_kernel_result! {
325+
// SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
326+
let dev = unsafe { Device::from_ptr(netdev) };
327+
// SAFETY: The value stored as driver data was returned by `into_pointer` during registration.
328+
let data = unsafe { T::Data::borrow(bindings::dev_get_drvdata(&mut (*netdev).dev)) };
329+
T::open(dev, data)?;
330+
Ok(0)
331+
}
299332
}
300333

301334
unsafe extern "C" fn stop_callback(netdev: *mut bindings::net_device) -> core::ffi::c_int {
302-
let ptr = unsafe { bindings::dev_get_drvdata(&mut (*netdev).dev) };
303-
let dev = unsafe { Device::from_ptr(netdev) };
304-
let data = unsafe { T::Data::borrow(ptr) };
305-
T::stop(dev, data)
335+
from_kernel_result! {
336+
// SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
337+
let dev = unsafe { Device::from_ptr(netdev) };
338+
// SAFETY: The value stored as driver data was returned by `into_pointer` during registration.
339+
let data = unsafe { T::Data::borrow(bindings::dev_get_drvdata(&mut (*netdev).dev)) };
340+
T::stop(dev, data)?;
341+
Ok(0)
342+
}
306343
}
307344

308345
unsafe extern "C" fn start_xmit_callback(
309346
skb: *mut bindings::sk_buff,
310347
netdev: *mut bindings::net_device,
311-
) -> core::ffi::c_int {
312-
let ptr = unsafe { bindings::dev_get_drvdata(&mut (*netdev).dev) };
348+
) -> bindings::netdev_tx_t {
349+
// SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
313350
let dev = unsafe { Device::from_ptr(netdev) };
351+
// SAFETY: The C API guarantees that `sk_buff` isn't released while this function is running.
314352
let skb = unsafe { SkBuff::from_ptr(skb) };
315-
let data = unsafe { T::Data::borrow(ptr) };
316-
T::start_xmit(skb, dev, data)
353+
// SAFETY: The value stored as driver data was returned by `into_pointer` during registration.
354+
let data = unsafe { T::Data::borrow(bindings::dev_get_drvdata(&mut (*netdev).dev)) };
355+
T::start_xmit(skb, dev, data) as bindings::netdev_tx_t
317356
}
318357
}
319358

359+
/// Driver transmit return codes.
360+
#[repr(i32)]
361+
pub enum NetdevTx {
362+
/// Driver took care of packet.
363+
Ok = bindings::netdev_tx_NETDEV_TX_OK,
364+
/// Driver tx path was busy.
365+
Busy = bindings::netdev_tx_NETDEV_TX_BUSY,
366+
}
367+
320368
// SAFETY: `Registration` does not expose any of its state across threads.
321369
unsafe impl<T: DeviceOperations> Sync for Registration<T> {}
322370

@@ -332,17 +380,17 @@ pub trait DeviceOperations {
332380
type Data: PointerWrapper + Send + Sync = ();
333381

334382
/// Corresponds to `ndo_open` in `struct net_device_ops`.
335-
fn open(dev: &Device, data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> i32;
383+
fn open(dev: &Device, data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result;
336384

337385
/// Corresponds to `ndo_stop` in `struct net_device_ops`.
338-
fn stop(dev: &Device, data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> i32;
386+
fn stop(dev: &Device, data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result;
339387

340388
/// Corresponds to `ndo_start_xmit` in `struct net_device_ops`.
341389
fn start_xmit(
342390
skb: &SkBuff,
343391
dev: &Device,
344392
data: <Self::Data as PointerWrapper>::Borrowed<'_>,
345-
) -> i32;
393+
) -> NetdevTx;
346394
}
347395

348396
/// Wraps the kernel's `struct net`.

0 commit comments

Comments
 (0)