public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver
@ 2026-04-02 16:36 Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 1/6] rust: bindings: expose networking headers needed by nlmon Wenzhao Liao
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Hi,

This RFC proposes a minimal set of Rust networking abstractions for
link-type drivers, together with a Rust implementation of nlmon as a
reference driver.

The scope is intentionally narrow. The series only tries to cover the
pieces needed to model:

- rtnl link registration and validation
- net_device private state allocation
- sk_buff transmit ownership
- netlink tap lifetime management
- per-device stats updates

nlmon is a useful target for this because it is small, self-contained,
and exercises rtnl registration, netdevice setup, tap lifecycle, and
stats handling without introducing hardware-specific probe or teardown
paths.

The series is structured as follows:

- patches 1-2 expose the required bindings and helper glue
- patches 3-4 add the minimal Rust net abstractions
- patch 5 adds the Rust nlmon reference driver
- patch 6 adds scoped MAINTAINERS entries

The driver itself is built with #![forbid(unsafe_code)] and does not
call raw bindings directly. Unsafe is confined to small abstraction
implementations under rust/kernel/net/.

Validation so far:

- drivers/net/nlmon_rust.o builds successfully
- x86_64 bzImage builds successfully
- QEMU smoke passes:
  ip link add nlmon0 type nlmon
  ip link set nlmon0 up
  ip link show nlmon0
  ip link set nlmon0 down
  ip link del nlmon0

The Rust implementation is kept behind CONFIG_NLMON_RUST so the new
abstractions and the reference driver can be reviewed without displacing
the existing C implementation.

Feedback on the abstraction shape, the lifetime model, and whether
nlmon is a suitable reference driver would be especially appreciated.

I would also be grateful for guidance on any aspect of this series that
does not match Rust-for-Linux or netdev expectations. If the direction
is useful but the submission, factoring, or abstraction boundary needs
to change, I am happy to revise the series accordingly and resubmit.

Thanks,
Wenzhao Liao

Wenzhao Liao (6):
  rust: bindings: expose networking headers needed by nlmon
  rust: helpers: add net_device and sk_buff helper wrappers
  rust: net: add minimal skbuff, netdevice, and stats abstractions
  rust: net: add minimal rtnl registration and netlink tap support
  net: add Rust reference driver for nlmon
  MAINTAINERS: add Rust net and nlmon entries

 MAINTAINERS                     |  19 ++
 drivers/net/Kconfig             |   9 +
 drivers/net/Makefile            |   6 +-
 drivers/net/nlmon_rust.rs       |  93 ++++++++++
 rust/bindings/bindings_helper.h |   4 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/net.c              |  19 ++
 rust/kernel/net.rs              |   5 +
 rust/kernel/net/netdevice.rs    | 319 ++++++++++++++++++++++++++++++++
 rust/kernel/net/netlink_tap.rs  |  89 +++++++++
 rust/kernel/net/rtnl.rs         | 221 ++++++++++++++++++++++
 rust/kernel/net/skbuff.rs       |  67 +++++++
 rust/kernel/net/stats.rs        |  17 ++
 13 files changed, 868 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/nlmon_rust.rs
 create mode 100644 rust/helpers/net.c
 create mode 100644 rust/kernel/net/netdevice.rs
 create mode 100644 rust/kernel/net/netlink_tap.rs
 create mode 100644 rust/kernel/net/rtnl.rs
 create mode 100644 rust/kernel/net/skbuff.rs
 create mode 100644 rust/kernel/net/stats.rs

-- 
2.34.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC PATCH 1/6] rust: bindings: expose networking headers needed by nlmon
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
@ 2026-04-02 16:36 ` Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 2/6] rust: helpers: add net_device and sk_buff helper wrappers Wenzhao Liao
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Expose the networking declarations consumed by the minimal Rust nlmon
reference driver before higher level wrappers are introduced.

This includes the core net_device, rtnl_link_ops, statistics, sk_buff,
and netlink tap declarations needed by the planned abstractions.

Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
 rust/bindings/bindings_helper.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 083cc44aa952..ee56505e03f9 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -57,6 +57,7 @@
 #include <linux/file.h>
 #include <linux/firmware.h>
 #include <linux/fs.h>
+#include <linux/if_arp.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/io-pgtable.h>
@@ -66,6 +67,8 @@
 #include <linux/mdio.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
 #include <linux/of_device.h>
 #include <linux/pci.h>
 #include <linux/phy.h>
@@ -88,6 +91,7 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/xarray.h>
+#include <net/rtnetlink.h>
 #include <trace/events/rust_sample.h>
 
 /*
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 2/6] rust: helpers: add net_device and sk_buff helper wrappers
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 1/6] rust: bindings: expose networking headers needed by nlmon Wenzhao Liao
@ 2026-04-02 16:36 ` Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 3/6] rust: net: add minimal skbuff, netdevice, and stats abstractions Wenzhao Liao
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Add C helper entry points for the small networking helpers that are not
exposed through bindgen-friendly interfaces.

This covers netdev_priv() and dev_lstats_add(), which are used by the
reference driver and remain hidden behind Rust-side safe wrappers.

Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
 rust/helpers/helpers.c |  1 +
 rust/helpers/net.c     | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)
 create mode 100644 rust/helpers/net.c

diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index a3c42e51f00a..90fe1c7cbadc 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -38,6 +38,7 @@
 #include "maple_tree.c"
 #include "mm.c"
 #include "mutex.c"
+#include "net.c"
 #include "of.c"
 #include "page.c"
 #include "pci.c"
diff --git a/rust/helpers/net.c b/rust/helpers/net.c
new file mode 100644
index 000000000000..da04c718acd4
--- /dev/null
+++ b/rust/helpers/net.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+__rust_helper void rust_helper_dev_kfree_skb(struct sk_buff *skb)
+{
+	dev_kfree_skb(skb);
+}
+
+__rust_helper void rust_helper_dev_lstats_add(struct net_device *dev, unsigned int len)
+{
+	dev_lstats_add(dev, len);
+}
+
+__rust_helper void *rust_helper_netdev_priv(const struct net_device *dev)
+{
+	return netdev_priv(dev);
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 3/6] rust: net: add minimal skbuff, netdevice, and stats abstractions
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 1/6] rust: bindings: expose networking headers needed by nlmon Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 2/6] rust: helpers: add net_device and sk_buff helper wrappers Wenzhao Liao
@ 2026-04-02 16:36 ` Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 4/6] rust: net: add minimal rtnl registration and netlink tap support Wenzhao Liao
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Add narrow Rust wrappers for sk_buff access, net_device private state,
and lightweight stats updates.

These APIs keep ownership with kernel-managed networking objects while
confining unsafe operations to the abstraction boundary.

Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
 rust/kernel/net.rs           |   3 +
 rust/kernel/net/netdevice.rs | 319 +++++++++++++++++++++++++++++++++++
 rust/kernel/net/skbuff.rs    |  67 ++++++++
 rust/kernel/net/stats.rs     |  17 ++
 4 files changed, 406 insertions(+)
 create mode 100644 rust/kernel/net/netdevice.rs
 create mode 100644 rust/kernel/net/skbuff.rs
 create mode 100644 rust/kernel/net/stats.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index fe415cb369d3..a61bc76f4499 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -4,3 +4,6 @@
 
 #[cfg(CONFIG_RUST_PHYLIB_ABSTRACTIONS)]
 pub mod phy;
+pub mod netdevice;
+pub mod skbuff;
+pub mod stats;
diff --git a/rust/kernel/net/netdevice.rs b/rust/kernel/net/netdevice.rs
new file mode 100644
index 000000000000..1e6a63741422
--- /dev/null
+++ b/rust/kernel/net/netdevice.rs
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Network device support.
+//!
+//! C headers: [`include/linux/netdevice.h`](srctree/include/linux/netdevice.h)
+
+use crate::{
+    bindings,
+    error::from_result,
+    net::skbuff,
+    prelude::*,
+    types::Opaque,
+};
+
+/// Network device feature flags.
+pub type Features = bindings::netdev_features_t;
+
+/// `features` bits used by the MVP link-type setup path.
+pub mod features {
+    use super::{bindings, Features};
+
+    const fn bit(index: u32) -> Features {
+        1u64 << index
+    }
+
+    /// Equivalent to `NETIF_F_SG`.
+    pub const SG: Features = bit(bindings::NETIF_F_SG_BIT as u32);
+
+    /// Equivalent to `NETIF_F_FRAGLIST`.
+    pub const FRAGLIST: Features = bit(bindings::NETIF_F_FRAGLIST_BIT as u32);
+
+    /// Equivalent to `NETIF_F_HIGHDMA`.
+    pub const HIGHDMA: Features = bit(bindings::NETIF_F_HIGHDMA_BIT as u32);
+}
+
+/// MTU-related constants and helpers used by the MVP link-type setup path.
+pub mod mtu {
+    use super::bindings;
+
+    const fn align(value: usize, alignment: usize) -> usize {
+        (value + alignment - 1) & !(alignment - 1)
+    }
+
+    /// Equivalent to `NLMSG_GOODSIZE`.
+    pub const fn nlmsg_goodsize() -> u32 {
+        let page = if bindings::PAGE_SIZE < 8192 {
+            bindings::PAGE_SIZE
+        } else {
+            8192
+        };
+        let overhead = align(
+            core::mem::size_of::<bindings::skb_shared_info>(),
+            bindings::SMP_CACHE_BYTES as usize,
+        );
+
+        (page - overhead) as u32
+    }
+
+    /// Equivalent to `sizeof(struct nlmsghdr)`.
+    pub const NLMSGHDR: u32 = core::mem::size_of::<bindings::nlmsghdr>() as u32;
+}
+
+/// `priv_flags` bits used by the MVP link-type setup path.
+pub mod priv_flags {
+    use super::bindings;
+
+    /// Equivalent to `IFF_NO_QUEUE`.
+    pub const NO_QUEUE: u32 = bindings::netdev_priv_flags_IFF_NO_QUEUE;
+}
+
+/// `flags` bits used by the MVP link-type setup path.
+pub mod flags {
+    use super::bindings;
+
+    /// Equivalent to `IFF_NOARP`.
+    pub const NO_ARP: u32 = bindings::net_device_flags_IFF_NOARP;
+}
+
+/// Device type constants used by the MVP link-type setup path.
+pub mod device_type {
+    use super::bindings;
+
+    /// Equivalent to `ARPHRD_NETLINK`.
+    pub const NETLINK: u16 = bindings::ARPHRD_NETLINK as u16;
+}
+
+/// Per-cpu stat type constants used by the MVP link-type setup path.
+pub mod pcpu_stat_type {
+    use super::bindings;
+
+    /// Equivalent to `NETDEV_PCPU_STAT_LSTATS`.
+    pub const LSTATS: bindings::netdev_stat_type =
+        bindings::netdev_stat_type_NETDEV_PCPU_STAT_LSTATS;
+}
+
+/// Result of an `ndo_start_xmit` callback.
+pub enum TxOutcome {
+    /// The skb has been consumed and may be dropped by the abstraction.
+    Ok,
+
+    /// The device is temporarily busy; ownership of the skb goes back to the networking core.
+    Busy(skbuff::SkBuff),
+}
+
+/// Operations exposed by a network device for the MVP `nlmon` loop.
+///
+/// The callback trampolines live in this abstraction layer so that driver code does not have to
+/// touch raw kernel pointers or private storage casts directly.
+pub trait Operations: Send + Sync + 'static {
+    /// The type stored in `net_device` private storage.
+    ///
+    /// The RTNL/netdevice allocation path zero-initializes private storage before any driver
+    /// callback observes it, so implementations must accept the all-zero bit pattern.
+    type Private: Zeroable;
+
+    /// Device open callback.
+    fn open(dev: &mut Device, private: Pin<&mut Self::Private>) -> Result;
+
+    /// Device stop callback.
+    fn stop(dev: &mut Device, private: Pin<&mut Self::Private>) -> Result;
+
+    /// Packet transmit callback.
+    ///
+    /// This only exposes a shared device view: TX callbacks may run concurrently, so the
+    /// abstraction must not synthesize an exclusive borrow of either `net_device` or private
+    /// driver state here.
+    fn start_xmit(skb: skbuff::SkBuff, dev: &Device) -> TxOutcome;
+}
+
+/// A Rust wrapper over `struct net_device`.
+///
+/// # Invariants
+///
+/// - The wrapped pointer always points to a valid `struct net_device`.
+/// - The caller is responsible for only creating references in contexts where the kernel allows
+///   the accessed fields to be mutated.
+#[repr(transparent)]
+pub struct Device(Opaque<bindings::net_device>);
+
+impl Device {
+    /// Creates a mutable wrapper from a raw `net_device` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must point to a valid `struct net_device` for the lifetime of the returned
+    /// reference, and the caller must ensure that it is safe to mutate through it.
+    pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::net_device) -> &'a mut Self {
+        let ptr = ptr.cast::<Self>();
+        // SAFETY: The caller guarantees the pointer is valid for the returned lifetime.
+        unsafe { &mut *ptr }
+    }
+
+    /// Creates a shared wrapper from a raw `net_device` pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must point to a valid `struct net_device` for the lifetime of the returned
+    /// reference.
+    pub(crate) unsafe fn from_raw_ref<'a>(ptr: *mut bindings::net_device) -> &'a Self {
+        let ptr = ptr.cast::<Self>();
+        // SAFETY: The caller guarantees the pointer is valid for the returned lifetime.
+        unsafe { &*ptr }
+    }
+
+    /// Returns the wrapped raw `net_device` pointer.
+    pub(crate) fn as_ptr(&self) -> *mut bindings::net_device {
+        self.0.get()
+    }
+
+    /// Sets `dev->type`.
+    pub fn set_type(&mut self, device_type: u16) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).type_ = device_type };
+    }
+
+    /// ORs a bit into `dev->priv_flags`.
+    pub fn add_priv_flag(&mut self, flag: u32) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`, and the
+        // bindgen-generated accessors preserve the layout of the `priv_flags/lltx` union.
+        unsafe {
+            let flags = &mut (*dev).__bindgen_anon_1.__bindgen_anon_1;
+            let current = flags.priv_flags();
+            let flag = flag as usize;
+            flags.set_priv_flags(current | flag);
+        }
+    }
+
+    /// Sets `dev->lltx`.
+    pub fn set_lltx(&mut self, enabled: bool) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`, and the
+        // bindgen-generated accessors preserve the layout of the `priv_flags/lltx` union.
+        unsafe {
+            let flags = &mut (*dev).__bindgen_anon_1.__bindgen_anon_1;
+            flags.set_lltx(if enabled { 1 } else { 0 });
+        }
+    }
+
+    /// Stores a typed `net_device_ops` vtable pointer into `dev->netdev_ops`.
+    pub fn set_netdevice_ops<T: Operations>(&mut self) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).netdev_ops = OperationsVTable::<T>::build() };
+    }
+
+    /// Sets `dev->needs_free_netdev`.
+    pub fn set_needs_free_netdev(&mut self, enabled: bool) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).needs_free_netdev = enabled };
+    }
+
+    /// Sets `dev->features`.
+    pub fn set_features(&mut self, features: Features) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).features = features };
+    }
+
+    /// Sets `dev->flags`.
+    pub fn set_flags(&mut self, flags: u32) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).flags = flags };
+    }
+
+    /// Sets `dev->mtu`.
+    pub fn set_mtu(&mut self, mtu: u32) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).mtu = mtu };
+    }
+
+    /// Sets `dev->min_mtu`.
+    pub fn set_min_mtu(&mut self, mtu: u32) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).min_mtu = mtu };
+    }
+
+    /// Sets `dev->pcpu_stat_type`.
+    pub fn set_pcpu_stat_type(&mut self, stat_type: bindings::netdev_stat_type) {
+        let dev = self.as_ptr();
+        // SAFETY: The type invariant guarantees that `dev` points to a valid `net_device`.
+        unsafe { (*dev).set_pcpu_stat_type(stat_type) };
+    }
+
+    /// Returns a typed raw pointer to `net_device` private storage.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the current `net_device` was allocated with private storage for
+    /// `T`. Dereferencing the returned pointer additionally requires exclusive access to that
+    /// storage.
+    pub(crate) unsafe fn private_ptr<T>(&self) -> *mut T {
+        // SAFETY: The caller guarantees that the private storage really contains a `T`, and the
+        // helper/exported wrapper preserves the C `netdev_priv` semantics.
+        unsafe { bindings::netdev_priv(self.as_ptr() as *const bindings::net_device).cast::<T>() }
+    }
+}
+
+struct OperationsVTable<T: Operations>(core::marker::PhantomData<T>);
+
+impl<T: Operations> OperationsVTable<T> {
+    extern "C" fn open_callback(dev: *mut bindings::net_device) -> c_int {
+        from_result(|| {
+            // SAFETY: The networking core only calls this callback with a valid `net_device`.
+            let dev = unsafe { Device::from_raw(dev) };
+            // SAFETY: The `rtnl::Registration<T>` abstraction ties `priv_size` to `T::Private`.
+            let private = unsafe { Pin::new_unchecked(&mut *dev.private_ptr::<T::Private>()) };
+            T::open(dev, private)?;
+            Ok(0)
+        })
+    }
+
+    extern "C" fn stop_callback(dev: *mut bindings::net_device) -> c_int {
+        from_result(|| {
+            // SAFETY: The networking core only calls this callback with a valid `net_device`.
+            let dev = unsafe { Device::from_raw(dev) };
+            // SAFETY: The `rtnl::Registration<T>` abstraction ties `priv_size` to `T::Private`.
+            let private = unsafe { Pin::new_unchecked(&mut *dev.private_ptr::<T::Private>()) };
+            T::stop(dev, private)?;
+            Ok(0)
+        })
+    }
+
+    extern "C" fn start_xmit_callback(
+        skb: *mut bindings::sk_buff,
+        dev: *mut bindings::net_device,
+    ) -> bindings::netdev_tx {
+        // SAFETY: The networking core only calls this callback with a valid `net_device`.
+        let dev = unsafe { Device::from_raw_ref(dev) };
+        // SAFETY: The networking core transfers ownership of the callback skb to the driver.
+        let skb = unsafe { skbuff::SkBuff::from_raw_owned(skb) };
+
+        match T::start_xmit(skb, dev) {
+            TxOutcome::Ok => bindings::netdev_tx_NETDEV_TX_OK,
+            TxOutcome::Busy(skb) => {
+                let _ = skb.into_raw();
+                bindings::netdev_tx_NETDEV_TX_BUSY
+            }
+        }
+    }
+
+    const VTABLE: bindings::net_device_ops = bindings::net_device_ops {
+        ndo_open: Some(Self::open_callback),
+        ndo_stop: Some(Self::stop_callback),
+        ndo_start_xmit: Some(Self::start_xmit_callback),
+        // SAFETY: A zeroed `net_device_ops` is valid because omitted callbacks are represented by
+        // null pointers and all remaining fields are plain data/pointers.
+        ..unsafe { core::mem::zeroed() }
+    };
+
+    pub(crate) const fn build() -> &'static bindings::net_device_ops {
+        &Self::VTABLE
+    }
+}
diff --git a/rust/kernel/net/skbuff.rs b/rust/kernel/net/skbuff.rs
new file mode 100644
index 000000000000..32ca2bb24a75
--- /dev/null
+++ b/rust/kernel/net/skbuff.rs
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Socket-buffer ownership wrappers.
+//!
+//! C header: [`include/linux/skbuff.h`](srctree/include/linux/skbuff.h)
+
+use crate::bindings;
+
+use core::ptr::NonNull;
+
+/// Owns a single `struct sk_buff` passed into Rust from `ndo_start_xmit`.
+///
+/// # Invariants
+///
+/// - `ptr` is either `None` after ownership was handed back to the networking core, or it points
+///   to a valid `struct sk_buff` exclusively owned by this value.
+/// - Dropping this wrapper releases the skb exactly once via `dev_kfree_skb`.
+pub struct SkBuff {
+    ptr: Option<NonNull<bindings::sk_buff>>,
+}
+
+impl SkBuff {
+    /// Creates an owned skb wrapper from the callback argument.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be a valid non-null skb pointer whose ownership is transferred to Rust for the
+    /// duration of the callback.
+    pub(crate) unsafe fn from_raw_owned(ptr: *mut bindings::sk_buff) -> Self {
+        Self {
+            // SAFETY: The caller guarantees ownership of a valid non-null skb pointer.
+            ptr: Some(unsafe { NonNull::new_unchecked(ptr) }),
+        }
+    }
+
+    fn ptr(&self) -> *mut bindings::sk_buff {
+        self.ptr
+            .expect("SkBuff ownership already transferred back to the core")
+            .as_ptr()
+    }
+
+    /// Returns `skb->len`.
+    pub fn len(&self) -> u32 {
+        // SAFETY: `Self` owns a valid skb until ownership is explicitly returned with `into_raw`.
+        unsafe { (*self.ptr()).len }
+    }
+
+    /// Hands ownership back to the networking core without freeing the skb.
+    pub(crate) fn into_raw(mut self) -> *mut bindings::sk_buff {
+        self.ptr
+            .take()
+            .expect("SkBuff ownership already transferred back to the core")
+            .as_ptr()
+    }
+}
+
+impl Drop for SkBuff {
+    fn drop(&mut self) {
+        let Some(ptr) = self.ptr.take() else {
+            return;
+        };
+
+        // SAFETY: `Self` owns the skb exactly once unless ownership has been transferred back to
+        // the networking core via `into_raw`.
+        unsafe { bindings::dev_kfree_skb(ptr.as_ptr()) };
+    }
+}
diff --git a/rust/kernel/net/stats.rs b/rust/kernel/net/stats.rs
new file mode 100644
index 000000000000..3e17f3b19c05
--- /dev/null
+++ b/rust/kernel/net/stats.rs
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Network-device statistics helpers.
+//!
+//! C header: [`include/linux/netdevice.h`](srctree/include/linux/netdevice.h)
+
+use crate::{
+    bindings,
+    net::netdevice,
+};
+
+/// Equivalent to `dev_lstats_add(dev, len)`.
+pub fn dev_lstats_add(dev: &netdevice::Device, len: u32) {
+    // SAFETY: The helper expects a valid `net_device *`; `netdevice::Device` maintains that
+    // invariant and the helper handles the required per-cpu synchronization internally.
+    unsafe { bindings::dev_lstats_add(dev.as_ptr(), len) };
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 4/6] rust: net: add minimal rtnl registration and netlink tap support
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
                   ` (2 preceding siblings ...)
  2026-04-02 16:36 ` [RFC PATCH 3/6] rust: net: add minimal skbuff, netdevice, and stats abstractions Wenzhao Liao
@ 2026-04-02 16:36 ` Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 5/6] net: add Rust reference driver for nlmon Wenzhao Liao
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Add the minimal pieces needed to register an rtnl link driver and to
attach or detach a netlink tap from a net_device.

The abstractions model kernel-owned registration lifetime and keep the
driver layer free of unsafe blocks.

Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
 rust/kernel/net.rs             |   2 +
 rust/kernel/net/netlink_tap.rs |  89 +++++++++++++
 rust/kernel/net/rtnl.rs        | 221 +++++++++++++++++++++++++++++++++
 3 files changed, 312 insertions(+)
 create mode 100644 rust/kernel/net/netlink_tap.rs
 create mode 100644 rust/kernel/net/rtnl.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index a61bc76f4499..35459816c518 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -5,5 +5,7 @@
 #[cfg(CONFIG_RUST_PHYLIB_ABSTRACTIONS)]
 pub mod phy;
 pub mod netdevice;
+pub mod netlink_tap;
+pub mod rtnl;
 pub mod skbuff;
 pub mod stats;
diff --git a/rust/kernel/net/netlink_tap.rs b/rust/kernel/net/netlink_tap.rs
new file mode 100644
index 000000000000..b26461937c6c
--- /dev/null
+++ b/rust/kernel/net/netlink_tap.rs
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Netlink tap lifecycle helpers.
+//!
+//! C header: [`include/linux/netlink.h`](srctree/include/linux/netlink.h)
+
+use crate::{
+    bindings,
+    error::to_result,
+    net::netdevice,
+    prelude::*,
+    types::Opaque,
+    ThisModule,
+};
+
+/// Owns a `struct netlink_tap` plus its registration state.
+#[pin_data]
+#[derive(Zeroable)]
+pub struct Tap {
+    #[pin]
+    inner: Opaque<bindings::netlink_tap>,
+    registered: bool,
+}
+
+impl Tap {
+    /// Creates an unregistered tap.
+    pub const fn new() -> Self {
+        Self {
+            inner: Opaque::zeroed(),
+            registered: false,
+        }
+    }
+
+    /// Returns whether the tap is currently registered.
+    pub fn is_registered(&self) -> bool {
+        self.registered
+    }
+
+    /// Registers the tap for the provided device.
+    pub fn add(
+        self: Pin<&mut Self>,
+        dev: &netdevice::Device,
+        module: &'static ThisModule,
+    ) -> Result {
+        // SAFETY: The caller pinned `self`, so accessing the interior through the stable address is
+        // valid for the duration of this method.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if this.registered {
+            return Err(EBUSY);
+        }
+
+        let tap = this.inner.get();
+
+        // SAFETY: `tap` points to valid storage for `struct netlink_tap`.
+        unsafe {
+            (*tap).dev = dev.as_ptr();
+            (*tap).module = module.as_ptr();
+        }
+
+        // SAFETY: `tap` points to a valid `struct netlink_tap`.
+        to_result(unsafe { bindings::netlink_add_tap(tap) })?;
+        this.registered = true;
+        Ok(())
+    }
+
+    /// Unregisters the tap if it is currently active.
+    pub fn remove(self: Pin<&mut Self>) -> Result {
+        // SAFETY: The caller pinned `self`, so accessing the interior through the stable address is
+        // valid for the duration of this method.
+        let this = unsafe { self.get_unchecked_mut() };
+
+        if !this.registered {
+            return Ok(());
+        }
+
+        let tap = this.inner.get();
+
+        // SAFETY: `self.inner` contains a valid `struct netlink_tap` previously passed to
+        // `netlink_add_tap`.
+        to_result(unsafe { bindings::netlink_remove_tap(tap) })?;
+        this.registered = false;
+
+        // SAFETY: The tap has been removed and `netlink_remove_tap` waited for in-flight users via
+        // `synchronize_net`, so restoring the zeroed unregistered state is valid.
+        unsafe { tap.write(core::mem::zeroed()) };
+        Ok(())
+    }
+}
diff --git a/rust/kernel/net/rtnl.rs b/rust/kernel/net/rtnl.rs
new file mode 100644
index 000000000000..f3bddd29874f
--- /dev/null
+++ b/rust/kernel/net/rtnl.rs
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! RTNL link-type registration support.
+//!
+//! C headers:
+//! - [`include/net/rtnetlink.h`](srctree/include/net/rtnetlink.h)
+//! - [`include/uapi/linux/if_link.h`](srctree/include/uapi/linux/if_link.h)
+
+use crate::{
+    bindings,
+    error::{from_result, to_result},
+    net::netdevice,
+    prelude::*,
+    types::Opaque,
+};
+
+use core::{
+    marker::PhantomData,
+    mem::size_of,
+};
+
+/// Typed link-level netlink attribute selector.
+#[derive(Clone, Copy)]
+pub struct LinkAttr(usize);
+
+impl LinkAttr {
+    /// Equivalent to `IFLA_ADDRESS`.
+    pub const ADDRESS: Self = Self(bindings::IFLA_ADDRESS as usize);
+
+    const fn as_index(self) -> usize {
+        self.0
+    }
+}
+
+/// Typed info-level netlink attribute selector.
+#[derive(Clone, Copy)]
+pub struct InfoAttr(usize);
+
+impl InfoAttr {
+    /// Equivalent to `IFLA_INFO_KIND`.
+    pub const KIND: Self = Self(bindings::IFLA_INFO_KIND as usize);
+
+    /// Equivalent to `IFLA_INFO_DATA`.
+    pub const DATA: Self = Self(bindings::IFLA_INFO_DATA as usize);
+
+    const fn as_index(self) -> usize {
+        self.0
+    }
+}
+
+const LINK_ATTR_TABLE_LEN: usize = bindings::__IFLA_MAX as usize;
+const INFO_ATTR_TABLE_LEN: usize = bindings::__IFLA_INFO_MAX as usize;
+
+/// Validation context for `rtnl_link_ops::validate`.
+pub struct ValidateContext<'a> {
+    link_attrs: NlAttrTable,
+    data_attrs: NlAttrTable,
+    extack: Option<&'a mut ExtAck>,
+}
+
+impl<'a> ValidateContext<'a> {
+    fn new(
+        link_attrs: NlAttrTable,
+        data_attrs: NlAttrTable,
+        extack: Option<&'a mut ExtAck>,
+    ) -> Self {
+        Self {
+            link_attrs,
+            data_attrs,
+            extack,
+        }
+    }
+
+    /// Returns whether a link-level netlink attribute is present.
+    pub fn has_link_attr(&self, attr: LinkAttr) -> bool {
+        self.link_attrs.has_attr_index(attr.as_index())
+    }
+
+    /// Returns whether an info-level netlink attribute is present.
+    pub fn has_info_attr(&self, attr: InfoAttr) -> bool {
+        self.data_attrs.has_attr_index(attr.as_index())
+    }
+
+    /// Returns the optional extack wrapper.
+    pub fn extack(&mut self) -> Option<&mut ExtAck> {
+        self.extack.as_deref_mut()
+    }
+}
+
+/// Safe view over the `struct nlattr *tb[]` / `data[]` arrays passed to validate callbacks.
+#[derive(Clone, Copy)]
+pub struct NlAttrTable {
+    raw: *mut *mut bindings::nlattr,
+    len: usize,
+}
+
+impl NlAttrTable {
+    fn new(raw: *mut *mut bindings::nlattr, len: usize) -> Self {
+        Self { raw, len }
+    }
+
+    /// Returns `true` if the attribute slot contains a non-null pointer.
+    fn has_attr_index(&self, attr: usize) -> bool {
+        if self.raw.is_null() || attr >= self.len {
+            return false;
+        }
+
+        // SAFETY: The RTNL core provides these arrays for validate callbacks. Indexing is kept in
+        // the abstraction layer so driver code does not perform raw pointer arithmetic.
+        unsafe { !(*self.raw.add(attr)).is_null() }
+    }
+
+}
+
+/// Wrapper over `struct netlink_ext_ack`.
+#[repr(transparent)]
+pub struct ExtAck(Opaque<bindings::netlink_ext_ack>);
+
+impl ExtAck {
+    /// Creates a mutable wrapper from a raw extack pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must be valid for the returned lifetime.
+    pub unsafe fn from_raw<'a>(ptr: *mut bindings::netlink_ext_ack) -> &'a mut Self {
+        let ptr = ptr.cast::<Self>();
+        // SAFETY: The caller guarantees validity for the returned lifetime.
+        unsafe { &mut *ptr }
+    }
+}
+
+/// A Rust RTNL link-type driver.
+pub trait Driver: netdevice::Operations {
+    /// The RTNL link kind, e.g. `"nlmon"`.
+    const KIND: &'static CStr;
+
+    /// Performs link-type setup.
+    fn setup(dev: &mut netdevice::Device);
+
+    /// Optional netlink validation.
+    fn validate(_ctx: &mut ValidateContext<'_>) -> Result {
+        Ok(())
+    }
+}
+
+/// Owns an RTNL link-type registration.
+#[pin_data(PinnedDrop)]
+pub struct Registration<T: Driver> {
+    #[pin]
+    ops: Opaque<bindings::rtnl_link_ops>,
+    _driver: PhantomData<T>,
+}
+
+// SAFETY: Shared references do not expose interior mutation beyond drop semantics.
+unsafe impl<T: Driver> Sync for Registration<T> {}
+
+// SAFETY: Registration and unregistration are handled by RTNL core code and can be performed from
+// the module init/exit path.
+unsafe impl<T: Driver> Send for Registration<T> {}
+
+impl<T: Driver> Registration<T> {
+    extern "C" fn setup_callback(dev: *mut bindings::net_device) {
+        // SAFETY: The RTNL core only calls setup with a valid `net_device`.
+        let dev = unsafe { netdevice::Device::from_raw(dev) };
+        dev.set_netdevice_ops::<T>();
+        T::setup(dev);
+    }
+
+    extern "C" fn validate_callback(
+        tb: *mut *mut bindings::nlattr,
+        data: *mut *mut bindings::nlattr,
+        extack: *mut bindings::netlink_ext_ack,
+    ) -> c_int {
+        from_result(|| {
+            let extack = if extack.is_null() {
+                None
+            } else {
+                // SAFETY: The RTNL core passes a valid extack pointer when non-null.
+                Some(unsafe { ExtAck::from_raw(extack) })
+            };
+            let mut ctx = ValidateContext::new(
+                NlAttrTable::new(tb, LINK_ATTR_TABLE_LEN),
+                NlAttrTable::new(data, INFO_ATTR_TABLE_LEN),
+                extack,
+            );
+            T::validate(&mut ctx)?;
+            Ok(0)
+        })
+    }
+
+    /// Creates a new RTNL registration object.
+    pub fn new() -> impl PinInit<Self, Error> {
+        build_assert!(!core::mem::needs_drop::<T::Private>());
+        try_pin_init!(Self {
+            ops <- Opaque::try_ffi_init(|ptr: *mut bindings::rtnl_link_ops| {
+                // SAFETY: All-zero is a valid initial state for the opaque RTNL ops structure.
+                unsafe { ptr.write(core::mem::zeroed()) };
+
+                // SAFETY: `ptr` is valid for writes for the duration of this initializer.
+                unsafe {
+                    (*ptr).kind = T::KIND.as_char_ptr();
+                    (*ptr).priv_size = size_of::<T::Private>();
+                    (*ptr).setup = Some(Self::setup_callback);
+                    (*ptr).validate = Some(Self::validate_callback);
+                }
+
+                // SAFETY: `ptr` now points to a fully initialized `rtnl_link_ops`.
+                to_result(unsafe { bindings::rtnl_link_register(ptr) })
+            }),
+            _driver: PhantomData,
+        })
+    }
+}
+
+#[pinned_drop]
+impl<T: Driver> PinnedDrop for Registration<T> {
+    fn drop(self: Pin<&mut Self>) {
+        // SAFETY: The existence of `self` guarantees a successful earlier registration.
+        unsafe { bindings::rtnl_link_unregister(self.ops.get()) };
+    }
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 5/6] net: add Rust reference driver for nlmon
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
                   ` (3 preceding siblings ...)
  2026-04-02 16:36 ` [RFC PATCH 4/6] rust: net: add minimal rtnl registration and netlink tap support Wenzhao Liao
@ 2026-04-02 16:36 ` Wenzhao Liao
  2026-04-02 16:36 ` [RFC PATCH 6/6] MAINTAINERS: add Rust net and nlmon entries Wenzhao Liao
  2026-04-02 20:00 ` [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Andrew Lunn
  6 siblings, 0 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Implement nlmon as a small Rust reference driver on top of the new
networking abstractions.

nlmon is a good validation target because it is netlink-centric and
exercises rtnl registration, netdevice setup, tap lifecycle, and packet
stats without hardware dependencies.

Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
 drivers/net/Kconfig       |  9 ++++
 drivers/net/Makefile      |  6 ++-
 drivers/net/nlmon_rust.rs | 93 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/nlmon_rust.rs

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 17108c359216..0eccd0af8b75 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -466,6 +466,15 @@ config NLMON
 	  diagnostics, etc. This is mostly intended for developers or support
 	  to debug netlink issues. If unsure, say N.
 
+config NLMON_RUST
+	bool "Rust implementation of nlmon"
+	depends on RUST && NLMON
+	help
+	  Select this option to build the Rust implementation of
+	  the nlmon driver instead of the original C version.
+	  This keeps a small reference driver available while the
+	  supporting Rust networking abstractions are reviewed.
+
 config NETKIT
 	bool "BPF-programmable network device"
 	depends on BPF_SYSCALL
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5b01215f6829..5d3357d56cc8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -38,7 +38,11 @@ obj-$(CONFIG_VXLAN) += vxlan/
 obj-$(CONFIG_GENEVE) += geneve.o
 obj-$(CONFIG_BAREUDP) += bareudp.o
 obj-$(CONFIG_GTP) += gtp.o
-obj-$(CONFIG_NLMON) += nlmon.o
+ifdef CONFIG_NLMON_RUST
+  obj-$(CONFIG_NLMON) += nlmon_rust.o
+else
+  obj-$(CONFIG_NLMON) += nlmon.o
+endif
 obj-$(CONFIG_PFCP) += pfcp.o
 obj-$(CONFIG_NET_VRF) += vrf.o
 obj-$(CONFIG_VSOCKMON) += vsockmon.o
diff --git a/drivers/net/nlmon_rust.rs b/drivers/net/nlmon_rust.rs
new file mode 100644
index 000000000000..d10e320c4635
--- /dev/null
+++ b/drivers/net/nlmon_rust.rs
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#![forbid(unsafe_code)]
+
+//! Rust netlink monitoring device.
+//!
+//! C version of this driver: [`drivers/net/nlmon.c`](./nlmon.c)
+
+use kernel::{
+    net::{netdevice, netlink_tap, rtnl, skbuff, stats},
+    prelude::*,
+};
+
+module! {
+    type: NlmonModule,
+    name: "nlmon_rust",
+    authors: [
+        "Daniel Borkmann <dborkman@redhat.com>",
+        "Mathieu Geli <geli@enseirb.fr>",
+    ],
+    description: "Rust netlink monitoring device",
+    license: "GPL v2",
+    alias: ["rtnl-link-nlmon"],
+}
+
+#[pin_data]
+struct NlmonModule {
+    #[pin]
+    registration: rtnl::Registration<NlmonDriver>,
+}
+
+impl kernel::InPlaceModule for NlmonModule {
+    fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
+        try_pin_init!(Self {
+            registration <- rtnl::Registration::new(),
+        })
+    }
+}
+
+struct NlmonDriver;
+
+#[pin_data]
+#[derive(Zeroable)]
+#[repr(C)]
+struct NlmonPriv {
+    #[pin]
+    tap: netlink_tap::Tap,
+}
+
+impl netdevice::Operations for NlmonDriver {
+    type Private = NlmonPriv;
+
+    fn open(dev: &mut netdevice::Device, private: Pin<&mut Self::Private>) -> Result {
+        private.project().tap.add(dev, &THIS_MODULE)
+    }
+
+    fn stop(_dev: &mut netdevice::Device, private: Pin<&mut Self::Private>) -> Result {
+        private.project().tap.remove()
+    }
+
+    fn start_xmit(skb: skbuff::SkBuff, dev: &netdevice::Device) -> netdevice::TxOutcome {
+        stats::dev_lstats_add(dev, skb.len());
+        netdevice::TxOutcome::Ok
+    }
+}
+
+impl rtnl::Driver for NlmonDriver {
+    const KIND: &'static CStr = c"nlmon";
+
+    fn setup(dev: &mut netdevice::Device) {
+        let features = netdevice::features::SG
+            | netdevice::features::FRAGLIST
+            | netdevice::features::HIGHDMA;
+
+        dev.set_type(netdevice::device_type::NETLINK);
+        dev.add_priv_flag(netdevice::priv_flags::NO_QUEUE);
+        dev.set_lltx(true);
+        dev.set_needs_free_netdev(true);
+        dev.set_features(features);
+        dev.set_flags(netdevice::flags::NO_ARP);
+        dev.set_pcpu_stat_type(netdevice::pcpu_stat_type::LSTATS);
+        dev.set_mtu(netdevice::mtu::nlmsg_goodsize());
+        dev.set_min_mtu(netdevice::mtu::NLMSGHDR);
+    }
+
+    fn validate(ctx: &mut rtnl::ValidateContext<'_>) -> Result {
+        if ctx.has_link_attr(rtnl::LinkAttr::ADDRESS) {
+            return Err(EINVAL);
+        }
+
+        Ok(())
+    }
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 6/6] MAINTAINERS: add Rust net and nlmon entries
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
                   ` (4 preceding siblings ...)
  2026-04-02 16:36 ` [RFC PATCH 5/6] net: add Rust reference driver for nlmon Wenzhao Liao
@ 2026-04-02 16:36 ` Wenzhao Liao
  2026-04-02 20:00 ` [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Andrew Lunn
  6 siblings, 0 replies; 9+ messages in thread
From: Wenzhao Liao @ 2026-04-02 16:36 UTC (permalink / raw)
  To: rust-for-linux, netdev
  Cc: linux-kernel, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
	aliceryhl, tmgross, dakr, andrew+netdev, davem, edumazet, kuba,
	pabeni

Add scoped maintainer entries for the new Rust networking abstraction
files and for the Rust nlmon reference driver.

This keeps future changes routed to the networking and Rust mailing
lists while also giving the new code paths a direct maintainer contact.

Signed-off-by: Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
---
 MAINTAINERS | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 77fdfcb55f06..d1c3eb61ea46 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18335,6 +18335,25 @@ X:	Documentation/devicetree/bindings/net/wireless/
 X:	drivers/net/can/
 X:	drivers/net/wireless/
 
+NETWORKING LINK-TYPE ABSTRACTIONS [RUST]
+M:	Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
+L:	netdev@vger.kernel.org
+L:	rust-for-linux@vger.kernel.org
+S:	Maintained
+F:	rust/kernel/net.rs
+F:	rust/kernel/net/netdevice.rs
+F:	rust/kernel/net/netlink_tap.rs
+F:	rust/kernel/net/rtnl.rs
+F:	rust/kernel/net/skbuff.rs
+F:	rust/kernel/net/stats.rs
+
+NLMON DRIVER [RUST]
+M:	Wenzhao Liao <wenzhaoliao@ruc.edu.cn>
+L:	netdev@vger.kernel.org
+L:	rust-for-linux@vger.kernel.org
+S:	Maintained
+F:	drivers/net/nlmon_rust.rs
+
 NETWORKING DRIVERS (WIRELESS)
 M:	Johannes Berg <johannes@sipsolutions.net>
 L:	linux-wireless@vger.kernel.org
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver
  2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
                   ` (5 preceding siblings ...)
  2026-04-02 16:36 ` [RFC PATCH 6/6] MAINTAINERS: add Rust net and nlmon entries Wenzhao Liao
@ 2026-04-02 20:00 ` Andrew Lunn
       [not found]   ` <APYAlQCNKK5EzEq6n4bgjqou.3.1775205609812.Hmail.2023000929@ruc.edu.cn>
  6 siblings, 1 reply; 9+ messages in thread
From: Andrew Lunn @ 2026-04-02 20:00 UTC (permalink / raw)
  To: Wenzhao Liao
  Cc: rust-for-linux, netdev, linux-kernel, ojeda, boqun, gary,
	bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, dakr,
	andrew+netdev, davem, edumazet, kuba, pabeni

On Thu, Apr 02, 2026 at 12:36:34PM -0400, Wenzhao Liao wrote:
> Hi,
> 
> This RFC proposes a minimal set of Rust networking abstractions for
> link-type drivers, together with a Rust implementation of nlmon as a
> reference driver.

nlmon exists. Why would we want a second implementation in Rust?

It seems like we keep getting Rust submissions for the sake of
submitting Rust. We never seem to get Rust code adding something new,
something which does not already exist.

Please, if you want to submit Rust code, find a device which does not
have a driver and write a driver for it, in Rust. Or find a protocol
described in an RFC which we don't implement, and write a Rust
implementation. Or find a new firewall rule which cannot be described
using the current code, and implement it in Rust.

Unless it is something new, i doubt it will get accepted.

       Andrew

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver
       [not found]   ` <APYAlQCNKK5EzEq6n4bgjqou.3.1775205609812.Hmail.2023000929@ruc.edu.cn>
@ 2026-04-03 14:56     ` Andrew Lunn
  0 siblings, 0 replies; 9+ messages in thread
From: Andrew Lunn @ 2026-04-03 14:56 UTC (permalink / raw)
  To: wenzhaoliao
  Cc: rust-for-linux, netdev, linux-kernel, ojeda, boqun, gary,
	bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, dakr,
	andrew+netdev, davem, edumazet, kuba, pabeni

On Fri, Apr 03, 2026 at 04:40:09PM +0800, wenzhaoliao wrote:
> Hi Andrew,
> 
> Thank you for the candid feedback. I completely understand and agree with your
> point. Introducing Rust just for the sake of rewriting existing, perfectly
> working C code is not the goal here.
> 
> To clarify, my primary motivation for submitting the nlmon driver was not to
> replace the C implementation, but rather to use it as a minimal, isolated
> testbed to validate the proposed Rust networking abstractions (the first part
> of the patch series). I wanted to ensure the abstractions were somewhat
> grounded in a real use case before attempting to write a driver for a
> completely new device.

We prefer to see real users of newly added code. So start implementing
this new drivers for new hardware. Introduce the Rust abstractions as
the driver needs them. We allow patchsets of up to 15 patches. And the
first patchset does not need to be a functioning driver. So implement
what you can within 15 patches. It does not matter if it does not even
send/receive frames. Maybe it will just probe, and setup the Rx and Tx
rings? Then submit another patchset of 15 patches, adding more
abstractions and using them in the driver. Eventually you will get to
a working very minimal driver.

You might want to be way ahead in terms of development compared to
submission. So you might have 45 to 60 patches in your tree, a very
minimum driver which you know actually works, and then start
submitting. But expect to be doing a lot of rewriting as you get
review comments.

What hardware do you have in mind?

	Andrew

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-04-03 14:56 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-02 16:36 [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Wenzhao Liao
2026-04-02 16:36 ` [RFC PATCH 1/6] rust: bindings: expose networking headers needed by nlmon Wenzhao Liao
2026-04-02 16:36 ` [RFC PATCH 2/6] rust: helpers: add net_device and sk_buff helper wrappers Wenzhao Liao
2026-04-02 16:36 ` [RFC PATCH 3/6] rust: net: add minimal skbuff, netdevice, and stats abstractions Wenzhao Liao
2026-04-02 16:36 ` [RFC PATCH 4/6] rust: net: add minimal rtnl registration and netlink tap support Wenzhao Liao
2026-04-02 16:36 ` [RFC PATCH 5/6] net: add Rust reference driver for nlmon Wenzhao Liao
2026-04-02 16:36 ` [RFC PATCH 6/6] MAINTAINERS: add Rust net and nlmon entries Wenzhao Liao
2026-04-02 20:00 ` [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver Andrew Lunn
     [not found]   ` <APYAlQCNKK5EzEq6n4bgjqou.3.1775205609812.Hmail.2023000929@ruc.edu.cn>
2026-04-03 14:56     ` Andrew Lunn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox