@@ -8,7 +8,12 @@
//! [`include/linux/skbuff.h`](../../../../include/linux/skbuff.h),
//! [`include/uapi/linux/if_link.h`](../../../../include/uapi/linux/if_link.h).
-use crate::{bindings, error::*, prelude::vtable, types::ForeignOwnable};
+use crate::{
+ bindings,
+ error::*,
+ prelude::vtable,
+ types::{ForeignOwnable, Opaque},
+};
use {core::ffi::c_void, core::marker::PhantomData};
/// Corresponds to the kernel's `struct net_device`.
@@ -179,6 +184,11 @@ pub fn set_ether_operations<U>(&mut self) -> Result
} else {
None
},
+ ndo_get_stats64: if <T>::HAS_GET_STATS64 {
+ Some(Self::get_stats64_callback)
+ } else {
+ None
+ },
// SAFETY: The rest is zeroed out to initialize `struct net_device_ops`,
// set `Option<&F>` to be `None`.
..unsafe { core::mem::MaybeUninit::<bindings::net_device_ops>::zeroed().assume_init() }
@@ -256,6 +266,22 @@ const fn build_device_ops() -> &'static bindings::net_device_ops {
let skb = unsafe { SkBuff::from_ptr(skb) };
T::start_xmit(&mut dev, data, skb) as bindings::netdev_tx_t
}
+
+ unsafe extern "C" fn get_stats64_callback(
+ netdev: *mut bindings::net_device,
+ stats: *mut bindings::rtnl_link_stats64,
+ ) {
+ // SAFETY: The C API guarantees that `netdev` is valid while this function is running.
+ let mut dev = unsafe { Device::from_ptr(netdev) };
+ // SAFETY: The returned pointer was initialized by `D::Data::into_foreign` when
+ // `Registration` object was created.
+ // `D::Data::from_foreign` is only called by the object was released.
+ // So we know `data` is valid while this function is running.
+ let data = unsafe { D::Data::borrow(dev.priv_data_ptr()) };
+ // SAFETY: for writing and nobody else will read or write to it.
+ let stats = unsafe { RtnlLinkStats64::from_ptr(stats) };
+ T::get_stats64(&mut dev, data, stats);
+ }
}
// SAFETY: `Registration` exposes only `Device` object which can be used from
@@ -305,6 +331,14 @@ fn start_xmit(
) -> TxCode {
TxCode::Busy
}
+
+ /// Corresponds to `ndo_get_stats64` in `struct net_device_ops`.
+ fn get_stats64(
+ _dev: &mut Device,
+ _data: <D::Data as ForeignOwnable>::Borrowed<'_>,
+ _stats: &mut RtnlLinkStats64,
+ ) {
+ }
}
/// Corresponds to the kernel's `struct sk_buff`.
@@ -355,6 +389,34 @@ fn drop(&mut self) {
}
}
+/// Corresponds to the kernel's `struct rtnl_link_stats64`.
+#[repr(transparent)]
+pub struct RtnlLinkStats64(Opaque<bindings::rtnl_link_stats64>);
+
+impl RtnlLinkStats64 {
+ /// Creates a new [`RtnlLinkStats64`] instance.
+ ///
+ /// # Safety
+ ///
+ /// For the duration of the lifetime 'a, the pointer must be valid for writing and nobody else
+ /// may read or write to the `rtnl_link_stats64` object.
+ unsafe fn from_ptr<'a>(ptr: *mut bindings::rtnl_link_stats64) -> &'a mut Self {
+ unsafe { &mut *(ptr as *mut Self) }
+ }
+
+ /// Updates TX stats.
+ pub fn set_tx_stats(&mut self, packets: u64, bytes: u64, errors: u64, dropped: u64) {
+ // SAFETY: We have exclusive access to the `rtnl_link_stats64`, so writing to it is okay.
+ unsafe {
+ let inner = Opaque::get(&self.0);
+ (*inner).tx_packets = packets;
+ (*inner).tx_bytes = bytes;
+ (*inner).tx_errors = errors;
+ (*inner).tx_dropped = dropped;
+ }
+ }
+}
+
/// Builds the kernel's `struct ethtool_ops`.
struct EtherOperationsAdapter<D, T> {
_p: PhantomData<(D, T)>,
get_stats64() is used to return the stats for user-space like the number of packets, which network device drivers are supposed to support. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> --- rust/kernel/net/dev.rs | 64 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-)