Skip to content

Commit 9baf06d

Browse files
committed
Add EthtoolOps Vtable
Signed-off-by: Finn Behrens <[email protected]>
1 parent eaeb239 commit 9baf06d

File tree

5 files changed

+275
-22
lines changed

5 files changed

+275
-22
lines changed

rust/kernel/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/cdev.h>
44
#include <linux/fs.h>
55
#include <linux/netdevice.h>
6+
#include <linux/ethtool.h>
67
#include <linux/module.h>
78
#include <linux/random.h>
89
#include <linux/slab.h>

rust/kernel/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub mod c_types;
4040
pub mod chrdev;
4141
mod error;
4242
pub mod file_operations;
43-
pub mod netdevice_operations;
43+
pub mod net;
4444
pub mod miscdev;
4545
pub mod pages;
4646

rust/kernel/netdevice_operations.rs renamed to rust/kernel/net/device.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,28 @@ use crate::error::{Error, KernelResult};
1313
use crate::sync::{CondVar, Ref, RefCounted};
1414
use crate::user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter};
1515

16+
use super::ethtool::EthToolOps;
17+
18+
pub(crate) fn from_kernel_result<T>(r: KernelResult<T>) -> T
19+
where
20+
T: TryFrom<c_types::c_int>,
21+
T::Error: core::fmt::Debug,
22+
{
23+
match r {
24+
Ok(v) => v,
25+
Err(e) => T::try_from(e.to_kernel_errno()).unwrap(),
26+
}
27+
}
28+
29+
macro_rules! from_kernel_result {
30+
($($tt:tt)*) => {{
31+
from_kernel_result((|| {
32+
$($tt)*
33+
})())
34+
}};
35+
}
36+
37+
1638
extern "C" {
1739
#[allow(improper_ctypes)]
1840
fn rust_helper_netdev_priv(dev: *const bindings::net_device) -> *mut c_types::c_void;
@@ -21,7 +43,6 @@ extern "C" {
2143
fn rust_helper_eth_hw_addr_random(dev: *const bindings::net_device);
2244
}
2345

24-
2546
/// interface name assignment types (sysfs name_assign_type attribute)
2647
#[repr(u8)]
2748
pub enum NetNameAssingType {
@@ -116,7 +137,7 @@ impl<T: NetDeviceAdapter> NetDevice<T> {
116137
///
117138
/// The pointer `ptr` must be non-null and valid for the lifetime of the object.
118139
/// The private data must be non-null and valid for the lifetime of the object and be of type T.
119-
unsafe fn from_ptr(ptr: *const bindings::net_device) -> Self {
140+
pub unsafe fn from_ptr(ptr: *const bindings::net_device) -> Self {
120141
// INVARIANTS: the safety contract ensures the type invariant will hold.
121142

122143
// TODO: parse private data
@@ -146,6 +167,8 @@ impl<I: NetDeviceAdapter> DerefMut for NetDevice<I> {
146167
pub trait NetDeviceAdapter: Sized {
147168
type Ops: NetDeviceOps<Self>;
148169

170+
type EthOps: EthToolOps<Self>;
171+
149172

150173
/// Callback to initialize the device
151174
/// function table is setup by the abstraction based on Self::Ops
@@ -174,30 +197,12 @@ impl SkBuff {
174197
/// # Safety
175198
///
176199
/// The pointer `ptr` must be non-null and valid for the lifetime of the object.
177-
unsafe fn from_ptr(ptr: *const bindings::sk_buff) -> Self {
200+
pub unsafe fn from_ptr(ptr: *const bindings::sk_buff) -> Self {
178201
// INVARIANTS: the safety contract ensures the type invariant will hold.
179202
Self { ptr }
180203
}
181204
}
182205

183-
fn from_kernel_result<T>(r: KernelResult<T>) -> T
184-
where
185-
T: TryFrom<c_types::c_int>,
186-
T::Error: core::fmt::Debug,
187-
{
188-
match r {
189-
Ok(v) => v,
190-
Err(e) => T::try_from(e.to_kernel_errno()).unwrap(),
191-
}
192-
}
193-
194-
macro_rules! from_kernel_result {
195-
($($tt:tt)*) => {{
196-
from_kernel_result((|| {
197-
$($tt)*
198-
})())
199-
}};
200-
}
201206

202207
unsafe extern "C" fn ndo_init_callback<T: NetDeviceAdapter>(
203208
dev: *mut bindings::net_device

rust/kernel/net/ethtool.rs

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Net Device Operations.
4+
//!
5+
//! C header: [`include/linux/netdevice.h`](../../../../include/linux/netdevice.h)
6+
7+
use core::convert::{TryFrom, TryInto};
8+
use core::{marker, mem, ops::Deref, ops::DerefMut, pin::Pin, ptr};
9+
10+
use crate::bindings;
11+
use crate::{c_types, CStr};
12+
use crate::error::{Error, KernelResult};
13+
use crate::sync::{CondVar, Ref, RefCounted};
14+
use crate::user_ptr::{UserSlicePtr, UserSlicePtrReader, UserSlicePtrWriter};
15+
16+
use super::device::{NetDeviceAdapter, NetDevice};
17+
18+
pub(crate) fn from_kernel_result<T>(r: KernelResult<T>) -> T
19+
where
20+
T: TryFrom<c_types::c_int>,
21+
T::Error: core::fmt::Debug,
22+
{
23+
match r {
24+
Ok(v) => v,
25+
Err(e) => T::try_from(e.to_kernel_errno()).unwrap(),
26+
}
27+
}
28+
29+
macro_rules! from_kernel_result {
30+
($($tt:tt)*) => {{
31+
from_kernel_result((|| {
32+
$($tt)*
33+
})())
34+
}};
35+
}
36+
37+
unsafe extern "C" fn get_drvinfo_callback<T: NetDeviceAdapter>(dev: *mut bindings::net_device, info: *mut bindings::ethtool_drvinfo) {
38+
T::EthOps::get_drvinfo(
39+
&NetDevice::<T>::from_ptr(dev),
40+
&mut EthtoolDrvinfo::from_ptr(info)
41+
);
42+
}
43+
44+
unsafe extern "C" fn get_ts_info_callback<T: NetDeviceAdapter>(dev: *mut bindings::net_device, info: *mut bindings::ethtool_ts_info) -> c_types::c_int {
45+
from_kernel_result! {
46+
T::EthOps::get_ts_info(
47+
&NetDevice::<T>::from_ptr(dev),
48+
&mut EthToolTsInfo::from_ptr(info)
49+
)?;
50+
Ok(0)
51+
}
52+
}
53+
54+
pub(crate) struct EthToolOperationsVtable<T: NetDeviceAdapter>(marker::PhantomData<T>);
55+
56+
impl<T: NetDeviceAdapter> EthToolOperationsVtable<T> {
57+
const VTABLE: bindings::ethtool_ops = bindings::ethtool_ops {
58+
_bitfield_align_1: [],
59+
_bitfield_1: bindings::__BindgenBitfieldUnit::<[u8; 1usize]>::new([0u8; 1usize]),
60+
supported_coalesce_params: 0,
61+
get_drvinfo: if T::EthOps::TO_USE.get_drvinfo {
62+
Some(get_drvinfo_callback::<T>)
63+
} else {
64+
None
65+
},
66+
get_regs_len: None,
67+
get_regs: None,
68+
get_wol: None,
69+
set_wol: None,
70+
get_msglevel: None,
71+
set_msglevel: None,
72+
nway_reset: None,
73+
get_link: None,
74+
get_link_ext_state: None,
75+
get_eeprom_len: None,
76+
get_eeprom: None,
77+
set_eeprom: None,
78+
get_coalesce: None,
79+
set_coalesce: None,
80+
get_ringparam: None,
81+
set_ringparam: None,
82+
get_pause_stats: None,
83+
get_pauseparam: None,
84+
set_pauseparam: None,
85+
self_test: None,
86+
get_strings: None,
87+
set_phys_id: None,
88+
get_ethtool_stats: None,
89+
begin: None,
90+
complete: None,
91+
get_priv_flags: None,
92+
set_priv_flags: None,
93+
get_sset_count: None,
94+
get_rxnfc: None,
95+
set_rxnfc: None,
96+
flash_device: None,
97+
reset: None,
98+
get_rxfh_key_size: None,
99+
get_rxfh_indir_size: None,
100+
get_rxfh: None,
101+
set_rxfh: None,
102+
get_rxfh_context: None,
103+
set_rxfh_context: None,
104+
get_channels: None,
105+
set_channels: None,
106+
get_dump_flag: None,
107+
get_dump_data: None,
108+
set_dump: None,
109+
get_ts_info: if T::EthOps::TO_USE.get_ts_info {
110+
Some(get_ts_info_callback::<T>)
111+
} else {
112+
None
113+
},
114+
get_module_info: None,
115+
get_module_eeprom: None,
116+
get_eee: None,
117+
set_eee: None,
118+
get_tunable: None,
119+
set_tunable: None,
120+
get_per_queue_coalesce: None,
121+
set_per_queue_coalesce: None,
122+
get_link_ksettings: None,
123+
set_link_ksettings: None,
124+
get_fecparam: None,
125+
set_fecparam: None,
126+
get_ethtool_phy_stats: None,
127+
get_phy_tunable: None,
128+
set_phy_tunable: None,
129+
};
130+
131+
/// Builds an instance of [`struct ethtool_ops`].
132+
///
133+
/// # Safety
134+
///
135+
/// The caller must ensure that the adapter is compatible with the way the device is registered.
136+
pub(crate) const unsafe fn build() -> &'static bindings::ethtool_ops {
137+
&Self::VTABLE
138+
}
139+
}
140+
141+
/// Represents which fields of [`struct ethtool_ops`] should pe populated with pointers.
142+
pub struct EthToolToUse {
143+
/// The `get_drvinfo` field of [`struct ethtool_ops`].
144+
pub get_drvinfo: bool,
145+
146+
pub get_ts_info: bool,
147+
}
148+
149+
pub const ETH_TOOL_USE_NONE: EthToolToUse = EthToolToUse {
150+
get_drvinfo: false,
151+
get_ts_info: false,
152+
};
153+
154+
/// Defines the [`EthToolOps::TO_USE`] field based on a list of fields to be populated.
155+
#[macro_export]
156+
macro_rules! declare_eth_tool_ops {
157+
() => {
158+
const TO_USE: $crate::netdevice_operations::EthToolToUse = $crate::netdevice_operations::ETH_TOOL_USE_NONE;
159+
};
160+
($($i:ident),+) => {
161+
const TO_USE: kernel::netdevice_operations::EthToolToUse =
162+
$crate::netdevice_operations::EthToolToUse {
163+
$($i: true),+ ,
164+
..$crate::netdevice_operations::ETH_TOOL_USE_NONE
165+
};
166+
};
167+
}
168+
169+
pub trait EthToolOps<T: NetDeviceAdapter>: Send + Sync + Sized {
170+
const TO_USE: EthToolToUse;
171+
172+
fn get_drvinfo(dev: &NetDevice<T>, info: &mut EthtoolDrvinfo);
173+
174+
fn get_ts_info(dev: &NetDevice<T>, info: &mut EthToolTsInfo) -> KernelResult<()>;
175+
}
176+
177+
pub struct EthToolTsInfo {
178+
ptr: *const bindings::ethtool_ts_info
179+
}
180+
181+
impl EthToolTsInfo {
182+
/// Constructs a new [`struct ethtool_ts_info`] wrapper.
183+
///
184+
/// # Safety
185+
///
186+
/// The pointer `ptr` must be non-null and valid for the lifetime of the object.
187+
pub unsafe fn from_ptr(ptr: *const bindings::ethtool_ts_info) -> Self {
188+
// INVARIANTS: the safety contract ensures the type invariant will hold.
189+
Self {
190+
ptr,
191+
}
192+
}
193+
}
194+
195+
impl Deref for EthToolTsInfo {
196+
type Target = bindings::ethtool_ts_info;
197+
198+
fn deref(&self) -> &Self::Target {
199+
// SAFETY: ptr is valid
200+
unsafe { self.ptr.as_ref() }.unwrap()
201+
}
202+
}
203+
204+
impl DerefMut for EthToolTsInfo {
205+
fn deref_mut(&mut self) -> &mut Self::Target {
206+
// SAFETY: ptr is valid
207+
unsafe { (self.ptr as *mut bindings::ethtool_ts_info).as_mut() }.unwrap()
208+
}
209+
}
210+
211+
pub struct EthtoolDrvinfo {
212+
ptr: *const bindings::ethtool_drvinfo
213+
}
214+
215+
impl EthtoolDrvinfo {
216+
/// Constructs a new [`struct ethtool_drvinfo`] wrapper.
217+
///
218+
/// # Safety
219+
///
220+
/// The pointer `ptr` must be non-null and valid for the lifetime of the object.
221+
pub unsafe fn from_ptr(ptr: *const bindings::ethtool_drvinfo) -> Self {
222+
// INVARIANTS: the safety contract ensures the type invariant will hold.
223+
Self {
224+
ptr,
225+
}
226+
}
227+
}
228+
229+
impl Deref for EthtoolDrvinfo {
230+
type Target = bindings::ethtool_drvinfo;
231+
232+
fn deref(&self) -> &Self::Target {
233+
// SAFETY: ptr is valid
234+
unsafe { self.ptr.as_ref() }.unwrap()
235+
}
236+
}
237+
238+
impl DerefMut for EthtoolDrvinfo {
239+
fn deref_mut(&mut self) -> &mut Self::Target {
240+
// SAFETY: ptr is valid
241+
unsafe { (self.ptr as *mut bindings::ethtool_drvinfo).as_mut() }.unwrap()
242+
}
243+
}

rust/kernel/net/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
pub mod ethtool;
3+
pub mod device;
4+

0 commit comments

Comments
 (0)