From nobody Tue Jun 16 02:34:53 2026 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0E9433B6DF for ; Wed, 15 Apr 2026 09:39:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245977; cv=none; b=Jli/In8JIzT44aEgB4gKsxOj++pKw3h5vRqdmMc4wN7tsCkSuxVLDmTwmws4USFvQt3txsmeJv/VITWBdElLxWFivKBtd+lNVPuRqzjB99XvOiLky2bexMSs6P6FqinS21u4fDBkLSWtMQW6Ca9sCsEqsomY9Dzc3D5BW2EAquI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245977; c=relaxed/simple; bh=pjbAO55XTwIKrveO3PbdZX0WLuUD19YrjQYqWj4r0aw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=F9fAYfwILR74U1tLEE67RbZ+TCN9mc0KrPdaXnS8wCNcwl9RPUbht0Dy0YiIBpgelAiz31glitHEzQu/KbzEWaiPR8XzD05CT2lLlNp+iezoCSHT9zSxhRc9QDVaucHpwHu7HGdWjr3VLPkyg5CWu3WQptwLpY9Fqe9O8+yNxME= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=F1MofJnc; arc=none smtp.client-ip=209.85.221.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="F1MofJnc" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-43d1ceb2ddfso6149998f8f.2 for ; Wed, 15 Apr 2026 02:39:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1776245973; x=1776850773; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Y0SpVJdizsDVLrsxZKoDmA13FbMhOjDZMUd96vsteDw=; b=F1MofJncUjgUZi+rIZIyhH8jqXi6BItJhPku7hHKjx+t/AZMErc2u9upH9hwvdGomm 4vAmbvlrLFw5pwzjRUKFmasoZOKr9F5E12JipIYyRT+C4Hm4RHrQBpRVCW+1p5IFYYAJ N/KKZGrE6cKsiascAhRaOflSGM8AWmpusMmXylLz7hzS8rWBCiyN0yLpWiSHHpcICYL9 HS8dW6W/ii3uzOGmRgbhUu1dVfXeV8sgNDB5w4dQBMZl6Ugyop1vsN5A+NrPp8+8osOQ 0EZ+5zGzOYr+bYKoA4jdtyFlcf9LQIYp/4WDK1e/pduVsr5Cf9yvMTSsJP7VzYu6tDec jiiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776245973; x=1776850773; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Y0SpVJdizsDVLrsxZKoDmA13FbMhOjDZMUd96vsteDw=; b=azNV9D3++rywGh9kT5BoRbpJuwMd5Zbp5G9C7Z1PZdjpM9jYsRYNhAmiajhjva1AMf zpBwwxQ0ai9zH+/YkaRMkPAtFqM6+pzsPaVt/D16SXVWFzRKQrS7p7HsadiYp1sBEqkH vd+2KWLzV+l+0yTU0z1yMSvR0kbY1/qClswo4yAHJwVR+u9XEmeSrXD9jOYiPS208C8D /fSoLHGTXFCGpp/OdMZ4R3XPHvP1ov3P/Bv0wBgcfS+lYcwaIW8+3k+XWA46LaNe/270 wAe8o3YpTcIF2FZ16chdrMVCsWw/BFf7ibqTmSI9aGt+YwxgYE9yzu84b8H5QnVzj2KL u3Kg== X-Gm-Message-State: AOJu0Yw1Me0DH1GvBrE+lATkYkqDZMuyDAf62jXzUY2ULGxT6/Zg5eoV EQZAXQPrr1+qPzAyB9erEAQYhR/54j0x3MIkugRECD0raVebGucmxQx9vpOVtr7+OUXePJpSB+U 29FO2LQRnpML9eDtZKw== X-Received: from wmcn8.prod.google.com ([2002:a05:600c:c0c8:b0:488:a988:5a23]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:c091:b0:488:a977:8d6 with SMTP id 5b1f17b1804b1-488d683662cmr207593395e9.19.1776245973300; Wed, 15 Apr 2026 02:39:33 -0700 (PDT) Date: Wed, 15 Apr 2026 09:37:51 +0000 In-Reply-To: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=15232; i=aliceryhl@google.com; h=from:subject:message-id; bh=pjbAO55XTwIKrveO3PbdZX0WLuUD19YrjQYqWj4r0aw=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBp31zNrmus/sufEicoc9Kd6GzpXU6laiuVIRFT7 VM1klZjQc6JAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCad9czQAKCRAEWL7uWMY5 RldjD/9AdyhCU9dhdkTvm5ulbdNBhL6bDmZ6IP4uzI9gnp/dAbsLpU9KCTrKrYEWoFS57bR4b96 Lv0uEm1MOE6y6FF83O6cK3bqJovZol8E4VBgcQaWi4rYgy0EJgrJms/uuBpCNh0gOGMju5bBilX YLYxGi/1rSHuRRuzsWrHABKD1kF27hbGppl5Zc9jqSNWzAmNd9gzwwR2O6g2cSGfUxysY5MtESV z/iX0zxV7eGCdUdnXlshPK+u1nIPHjRoylqExh7mJf9WF1wUJA1gr3GmntejYT8TZOIDSHCqFK9 1KS5xizB8obEYV3bi/MEDcld96cAKy/pWmiu3rWxrI3XQ9aDHuC01R+BPHWN/leRS8eeL1kSCJl 8ditNZrfTzOOkUwhEfg7FQk3zQSZ8MAg9mC1oTY5eDLJMNGhoERRU292X9P9m/8I22Hi4P32w2t 5GY8V7Z4cUwuFfVzigIJeJo1JS0IIuWFN+CzPbryT08B1UNh0EL5/ugn6sxGRR/Jpb2la0Z53IG DFSc512jKUuBYaz7dslfizPey19a3m7K7vqBmt0qHA5Q1M5e7RCmOFBzYyWF+gJYNU4+mVSNzRc YR6SP4y2em43rCmWUr7qaOUL35TYPB7u7dnIFS0rrMpNJycauL/KfB+uxE5zJ9BMVT4IQ98z78D AVvAxLP9JFm9ISw== X-Mailer: b4 0.14.3 Message-ID: <20260415-binder-netlink-v3-1-84be9ba63ee2@google.com> Subject: [PATCH v3 1/4] rust: netlink: add raw netlink abstraction From: Alice Ryhl To: Miguel Ojeda , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Donald Hunter , Jakub Kicinski , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Christian Brauner , Carlos Llamas Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, netdev@vger.kernel.org, Alice Ryhl Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This implements a safe and relatively simple API over the netlink API, that allows you to add different attributes to a netlink message and broadcast it. As the first user of this API only makes use of broadcast, only broadcast messages are supported here. This API is intended to be safe and to be easy to use in *generated* code. This is because netlink is generally used with yaml files that describe the underlying API, and the python generator outputs C code (or, soon, Rust code) that lets you use the API more easily. So for example, if there is a string field, the code generator will output a method that internall calls `put_string()` with the right attr type. Signed-off-by: Alice Ryhl Reviewed-by: Andrew Lunn Reviewed-by: Matthew Maurer --- rust/bindings/bindings_helper.h | 3 + rust/helpers/genetlink.c | 46 ++++++ rust/helpers/helpers.c | 1 + rust/kernel/lib.rs | 1 + rust/kernel/netlink.rs | 329 ++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 380 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 083cc44aa952..8abb626fce6c 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -88,6 +88,8 @@ #include #include #include +#include +#include #include =20 /* @@ -105,6 +107,7 @@ const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN =3D ARCH_SLAB_MINALIGN; const size_t RUST_CONST_HELPER_ARCH_KMALLOC_MINALIGN =3D ARCH_KMALLOC_MINA= LIGN; const size_t RUST_CONST_HELPER_PAGE_SIZE =3D PAGE_SIZE; +const size_t RUST_CONST_HELPER_GENLMSG_DEFAULT_SIZE =3D GENLMSG_DEFAULT_SI= ZE; const gfp_t RUST_CONST_HELPER_GFP_ATOMIC =3D GFP_ATOMIC; const gfp_t RUST_CONST_HELPER_GFP_KERNEL =3D GFP_KERNEL; const gfp_t RUST_CONST_HELPER_GFP_KERNEL_ACCOUNT =3D GFP_KERNEL_ACCOUNT; diff --git a/rust/helpers/genetlink.c b/rust/helpers/genetlink.c new file mode 100644 index 000000000000..3530b69f6cf7 --- /dev/null +++ b/rust/helpers/genetlink.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2026 Google LLC. + */ + +#include + +#ifdef CONFIG_NET + +__rust_helper struct sk_buff *rust_helper_genlmsg_new(size_t payload, gfp_= t flags) +{ + return genlmsg_new(payload, flags); +} + +__rust_helper +int rust_helper_genlmsg_multicast(const struct genl_family *family, + struct sk_buff *skb, u32 portid, + unsigned int group, gfp_t flags) +{ + return genlmsg_multicast(family, skb, portid, group, flags); +} + +__rust_helper void rust_helper_genlmsg_cancel(struct sk_buff *skb, void *h= dr) +{ + genlmsg_cancel(skb, hdr); +} + +__rust_helper void rust_helper_genlmsg_end(struct sk_buff *skb, void *hdr) +{ + genlmsg_end(skb, hdr); +} + +__rust_helper void rust_helper_nlmsg_free(struct sk_buff *skb) +{ + nlmsg_free(skb); +} + +__rust_helper +int rust_helper_genl_has_listeners(const struct genl_family *family, + struct net *net, unsigned int group) +{ + return genl_has_listeners(family, net, group); +} + +#endif diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index a3c42e51f00a..0813185d8760 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -32,6 +32,7 @@ #include "err.c" #include "irq.c" #include "fs.c" +#include "genetlink.c" #include "io.c" #include "jump_label.c" #include "kunit.c" diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index d93292d47420..f5ea0ae0b6b7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -122,6 +122,7 @@ pub mod module_param; #[cfg(CONFIG_NET)] pub mod net; +pub mod netlink; pub mod num; pub mod of; #[cfg(CONFIG_PM_OPP)] diff --git a/rust/kernel/netlink.rs b/rust/kernel/netlink.rs new file mode 100644 index 000000000000..21f959c95fdc --- /dev/null +++ b/rust/kernel/netlink.rs @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2026 Google LLC. + +//! Rust support for generic netlink. +//! +//! Currently only supports exposing multicast groups. +//! +//! C header: [`include/net/genetlink.h`](srctree/include/net/genetlink.h) +#![cfg(CONFIG_NET)] + +use kernel::{ + alloc::{self, AllocError}, + error::to_result, + prelude::*, + transmute::AsBytes, + types::Opaque, + ThisModule, +}; + +use core::{ + mem::ManuallyDrop, + ptr::NonNull, // +}; + +/// The default netlink message size. +pub const GENLMSG_DEFAULT_SIZE: usize =3D bindings::GENLMSG_DEFAULT_SIZE; + +/// A wrapper around `struct sk_buff` for generic netlink messages. +/// +/// This type is intended to be specific for buffers used with netlink onl= y, and other usecases for +/// `struct sk_buff` are out-of-scope for this abstraction. +/// +/// # Invariants +/// +/// The pointer has ownership over a valid `sk_buff`. +pub struct NetlinkSkBuff { + skb: NonNull, +} + +impl NetlinkSkBuff { + /// Creates a new `NetlinkSkBuff` with the given size. + pub fn new(size: usize, flags: alloc::Flags) -> Result { + // SAFETY: `genlmsg_new` only requires its arguments to be valid i= ntegers. + let skb =3D unsafe { bindings::genlmsg_new(size, flags.as_raw()) }; + let skb =3D NonNull::new(skb).ok_or(AllocError)?; + Ok(NetlinkSkBuff { skb }) + } + + /// Puts a generic netlink header into the `NetlinkSkBuff`. + pub fn genlmsg_put( + self, + portid: u32, + seq: u32, + family: &'static Family, + cmd: u8, + ) -> Result { + let skb =3D self.skb.as_ptr(); + // SAFETY: The skb and family pointers are valid. + let hdr =3D unsafe { bindings::genlmsg_put(skb, portid, seq, famil= y.as_raw(), 0, cmd) }; + let hdr =3D NonNull::new(hdr).ok_or(AllocError)?; + Ok(GenlMsg { skb: self, hdr }) + } +} + +impl Drop for NetlinkSkBuff { + fn drop(&mut self) { + // SAFETY: We have ownership over the `sk_buff`, so we may free it. + unsafe { bindings::nlmsg_free(self.skb.as_ptr()) } + } +} + +/// A generic netlink message being constructed. +/// +/// # Invariants +/// +/// `hdr` references the header in this netlink message. +pub struct GenlMsg { + skb: NetlinkSkBuff, + hdr: NonNull, +} + +impl GenlMsg { + /// Puts an attribute into the message. + #[inline] + fn put(&mut self, attrtype: c_int, value: &T) -> Result + where + T: ?Sized + AsBytes, + { + let skb =3D self.skb.skb.as_ptr(); + let len =3D size_of_val(value); + let ptr =3D core::ptr::from_ref(value).cast::(); + // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and = the provided value is + // readable and initialized for its `size_of` bytes. + to_result(unsafe { bindings::nla_put(skb, attrtype, len as c_int, = ptr) }) + } + + /// Puts a `u32` attribute into the message. + #[inline] + pub fn put_u32(&mut self, attrtype: c_int, value: u32) -> Result { + self.put(attrtype, &value) + } + + /// Puts a string attribute into the message. + #[inline] + pub fn put_string(&mut self, attrtype: c_int, value: &CStr) -> Result { + self.put(attrtype, value.to_bytes_with_nul()) + } + + /// Puts a flag attribute into the message. + #[inline] + pub fn put_flag(&mut self, attrtype: c_int) -> Result { + let skb =3D self.skb.skb.as_ptr(); + // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and = a null pointer is valid + // when the length is zero. + to_result(unsafe { bindings::nla_put(skb, attrtype, 0, core::ptr::= null()) }) + } + + /// Sends the generic netlink message as a multicast message. + #[inline] + pub fn multicast( + self, + family: &'static Family, + portid: u32, + group: u32, + flags: alloc::Flags, + ) -> Result { + let me =3D ManuallyDrop::new(self); + // SAFETY: The `skb` and `family` pointers are valid. We pass owne= rship of the `skb` to + // `genlmsg_multicast` by not dropping `self`. + unsafe { + bindings::genlmsg_end(me.skb.skb.as_ptr(), me.hdr.as_ptr()); + to_result(bindings::genlmsg_multicast( + family.as_raw(), + me.skb.skb.as_ptr(), + portid, + group, + flags.as_raw(), + )) + } + } +} +impl Drop for GenlMsg { + fn drop(&mut self) { + // SAFETY: The `hdr` pointer references the header of this generic= netlink message. + unsafe { bindings::genlmsg_cancel(self.skb.skb.as_ptr(), self.hdr.= as_ptr()) }; + } +} + +/// Flags for a generic netlink family. +struct FamilyFlags { + /// Whether the family supports network namespaces. + netnsok: bool, + /// Whether the family supports parallel operations. + parallel_ops: bool, +} + +impl FamilyFlags { + /// Converts the flags to the bitfield representation used by `genl_fa= mily`. + const fn into_bitfield(self) -> bindings::__BindgenBitfieldUnit<[u8; 1= ]> { + // The below shifts are verified correct by test_family_flags_bitf= ield() below. + // + // Although bindgen generates helpers to change bitfields based on= the C headers, these + // helpers unfortunately can't be used in const context. Since `Fa= mily` needs to be filled + // out at build-time, we use this helper instead. + let mut bits =3D 0; + if self.netnsok { + bits |=3D 1 << 0; + } + if self.parallel_ops { + bits |=3D 1 << 1; + } + // SAFETY: This bitfield is represented as an u8. + unsafe { core::mem::transmute::>(bits) } + } +} + +/// A generic netlink family. +#[repr(transparent)] +pub struct Family { + inner: Opaque, +} + +// SAFETY: The `Family` type is thread safe. +unsafe impl Sync for Family {} + +impl Family { + /// Creates a new `Family` instance. + pub const fn const_new( + module: &ThisModule, + name: &[u8], + version: u32, + mcgrps: &'static [MulticastGroup], + ) -> Family { + let n_mcgrps =3D mcgrps.len() as u8; + if n_mcgrps as usize !=3D mcgrps.len() { + panic!("too many mcgrps"); + } + let mut genl_family =3D bindings::genl_family { + version, + _bitfield_1: FamilyFlags { + netnsok: true, + parallel_ops: true, + } + .into_bitfield(), + module: module.as_ptr(), + mcgrps: mcgrps.as_ptr().cast(), + n_mcgrps, + ..pin_init::zeroed() + }; + if CStr::from_bytes_with_nul(name).is_err() { + panic!("genl_family name not nul-terminated"); + } + if genl_family.name.len() < name.len() { + panic!("genl_family name too long"); + } + let mut i =3D 0; + while i < name.len() { + genl_family.name[i] =3D name[i]; + i +=3D 1; + } + Family { + inner: Opaque::new(genl_family), + } + } + + /// Checks if there are any listeners for the given multicast group. + pub fn has_listeners(&self, group: u32) -> bool { + // SAFETY: The family and init_net pointers are valid. + unsafe { + bindings::genl_has_listeners(self.as_raw(), &raw mut bindings:= :init_net, group) !=3D 0 + } + } + + /// Returns a raw pointer to the underlying `genl_family` structure. + pub fn as_raw(&self) -> *mut bindings::genl_family { + self.inner.get() + } +} + +/// A generic netlink multicast group. +#[repr(transparent)] +pub struct MulticastGroup { + // No Opaque because fully immutable + group: bindings::genl_multicast_group, +} + +// SAFETY: Pure data so thread safe. +unsafe impl Sync for MulticastGroup {} + +impl MulticastGroup { + /// Creates a new `MulticastGroup` instance. + pub const fn const_new(name: &CStr) -> MulticastGroup { + let mut group: bindings::genl_multicast_group =3D pin_init::zeroed= (); + + let name =3D name.to_bytes_with_nul(); + if group.name.len() < name.len() { + panic!("genl_multicast_group name too long"); + } + let mut i =3D 0; + while i < name.len() { + group.name[i] =3D name[i]; + i +=3D 1; + } + + MulticastGroup { group } + } +} + +/// A registration of a generic netlink family. +/// +/// This type represents the registration of a [`Family`]. When an instanc= e of this type is +/// dropped, its respective generic netlink family will be unregistered fr= om the system. +/// +/// # Invariants +/// +/// `self.family` always holds a valid reference to an initialized and reg= istered [`Family`]. +pub struct Registration { + family: &'static Family, +} + +impl Family { + /// Registers the generic netlink family with the kernel. + pub fn register(&'static self) -> Result { + // SAFETY: `self.as_raw()` is a valid pointer to a `genl_family` s= truct. + // The `genl_family` struct is static, so it will outlive the regi= stration. + to_result(unsafe { bindings::genl_register_family(self.as_raw()) }= )?; + Ok(Registration { family: self }) + } +} + +impl Drop for Registration { + fn drop(&mut self) { + // SAFETY: `self.family.as_raw()` is a valid pointer to a register= ed `genl_family` struct. + // The `Registration` struct ensures that `genl_unregister_family`= is called exactly once + // for this family when it goes out of scope. + unsafe { bindings::genl_unregister_family(self.family.as_raw()) }; + } +} + +#[macros::kunit_tests(rust_netlink)] +mod tests { + use super::*; + + #[test] + fn test_family_flags_bitfield() { + for netnsok in [false, true] { + for parallel_ops in [false, true] { + let mut b_fam =3D bindings::genl_family { + ..Default::default() + }; + b_fam.set_netnsok(if netnsok { 1 } else { 0 }); + b_fam.set_parallel_ops(if parallel_ops { 1 } else { 0 }); + + let c_bitfield =3D FamilyFlags { + netnsok, + parallel_ops, + } + .into_bitfield(); + + // SAFETY: The bit field is stored as u8. + let b_val: u8 =3D unsafe { core::mem::transmute(b_fam._bit= field_1) }; + // SAFETY: The bit field is stored as u8. + let c_val: u8 =3D unsafe { core::mem::transmute(c_bitfield= ) }; + assert_eq!(b_val, c_val); + } + } + } +} --=20 2.54.0.rc0.605.g598a273b03-goog From nobody Tue Jun 16 02:34:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E997933B6F9 for ; Wed, 15 Apr 2026 09:39:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245979; cv=none; b=GBjME4Vn6xPzLHLtBBUXgDhhM3bWpATSN/vpbrQWYhbXqagpEYngnqhDs3a5/BKUchI+iVKd0zJqffTGkBBmlB/Iqm2s6sCpEiy1aOKiHAFgMYJWnlyuTR9v52Xu2DH/r1zoh4SnWjRYWkvPvYT3VKcekJZp9Ck+Z/LkhwaReLU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245979; c=relaxed/simple; bh=pYERZwVis0sfOfVf5rbB7rXtctv5TUqHOfYeJEFG54Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=XSJqoFyu+LpwW+aa+3TyhgGwP+0r1ehDroDFQcv3Lp2AFEz6EoZjy/Ik/Ys3LuHT0w896JtsG4Pgam4iyJNV/97jFbFWTufyCxFukKvpy5Vrq/A7WkBJMbakhb9pCDgF7Foiy6hGw+sdV/xpeEDCWnM5XPIgRevTL1hd7GbN8aQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qeyt6jHZ; arc=none smtp.client-ip=209.85.208.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qeyt6jHZ" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-66c06661495so6113946a12.2 for ; Wed, 15 Apr 2026 02:39:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1776245975; x=1776850775; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=tOHvc+UXkFcaiR1CPEBZRUJAR3W/AL9Q6jZjmIFzwd4=; b=qeyt6jHZOG2ZgGMqXaJbJ6LS2+jH5KwB558Btvv4nVXODm8pZhlv8ygd5pWgQUF5BE w2SY0Aay6WWhNu4qYdPegtj2QdiUPOLZbPYxLlF5XBZNYkoR+5zYp/fETlPHa+8wrTT6 BUeSbh0RZrwlP8bsUhtBR0pHmRslU2ueEwbepNerb+LJ4mH32JqF7leSLsvq5v0gfJkQ c26K0W76jM1CUsdpzqIX+E1R99HL9IvwdMOKAa4XsRMCb73VyptZDqLb02IrAoT1SrFm FgUTcroYX6wdsriZKtmCoUvfO2pE6EyVFL19vglz0FnHVhVIhdDtuBZvdIZv3LbiFSuV pOKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776245975; x=1776850775; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tOHvc+UXkFcaiR1CPEBZRUJAR3W/AL9Q6jZjmIFzwd4=; b=VZJG37OUzanAWmahlGsa/nIckKTtvBz2qAA91BXeHQuzAGLiPB0DjK/Nlk0AKUqOAd tq3MVsOpJAAP1Gl2uPeMojigCNfXDLTJ3R+TwbdDh66lVh0X3IQOxx2bC8BkNJ/yKjmq PAoJUZSwvsh5BJTXd8BqubNPaa70DKN58Czs5/OiKJ12vr3bGg67j19f5dbRArSa2OtJ 4mabGZa8itvOziLelXIPBWBrc9ZxBLgPB05K/giF5g74SRJ44OHeNtlaevhBWSCxHzmc paqVJtOEeowpwTQ3zlLxsvcaKZ+HP1GigOMv+nVI2RAhBB5M65MYumzYP8X6IZ6wVZkg eFDg== X-Gm-Message-State: AOJu0YzAAQTlc+tjV7pagWXaM1+KLHGYJkdSWAPgQrFptZnseP73tZpM R6sATb42JxSJN1thULQZhAsCaDdipVtGeV4rMtk/J0Zhn6XY8YDCZciZJmGPRFfVUDz3qr9ha4g cogB6GulYPqnX87XldQ== X-Received: from eddo19.prod.google.com ([2002:a05:6402:5613:b0:669:e76e:1fc1]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:4409:b0:66d:3ebe:3f18 with SMTP id 4fb4d7f45d1cf-6707a471cffmr10854613a12.25.1776245974941; Wed, 15 Apr 2026 02:39:34 -0700 (PDT) Date: Wed, 15 Apr 2026 09:37:52 +0000 In-Reply-To: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7884; i=aliceryhl@google.com; h=from:subject:message-id; bh=pYERZwVis0sfOfVf5rbB7rXtctv5TUqHOfYeJEFG54Y=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBp31zOwI1Z/qaXVGkJIb+gdFwKml7bNTySwX69G 2ICiC51d42JAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCad9czgAKCRAEWL7uWMY5 RiU7EACgpzsMvxPt41bivzL0Ky3Ir1wanoaWgKiUkEaTa9qcCksjaXn+nwG8UHENQNVUdmjxj0H 2e+Nixx06lM/jaCHbn+i70GZIdbXOBvpMy88IiFUbhCBkmGnFwkdk2MVNTWxf0IvbIycPVI26EQ IVP7dtKeIQmWl2SdAXrNMW5SrG2hMCn3l8qWY6KFxmgY39JhK0QhDyspdiLfKbkAQqa3qzknZ5h x6WbRw2MeyFGMo+gkhnPB+yiE8FmqYoY8Aw4vtl4Ryy6r/UWVnKECilnbl8tSjJgT1VhtNJdEWF X2dVhEGRpBJWrY5CUT2L3pc/BO0tcekb7m0ubJy+2LUrelV7hxqpwCV7mY/5KiRGaeK8DLIFVOY lpnhgie+tdEhRkY3g5LE52t+0scgU2CGFcN82nVUqIK+8l6Rg3HXbbCwKkaPbGNuN7sehlkL/g2 y8OK2mW9yJzqKQfgFXDeC2SVb0aaoCGRD2jqMCl3ZI4hyumbaTC1cDERa4XDl/SGBgchj0pnyUz +e4Y5eah6cbtZ+vZ3/0kexizpAaqwdWRH0NFA7St1gwz092UNWmHn7JXBM1BnATnsQvTmfe6ctp tKklg5CoO+DXV/wfX3IRDE7dj3ub2RuIzJynjsWY07mWe7a34rIzDKFaBOwlkWeUzzD3eNxADcf 2sGuJUCBT8rA6Iw== X-Mailer: b4 0.14.3 Message-ID: <20260415-binder-netlink-v3-2-84be9ba63ee2@google.com> Subject: [PATCH v3 2/4] ynl_gen: generate Rust files from yaml files From: Alice Ryhl To: Miguel Ojeda , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Donald Hunter , Jakub Kicinski , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Christian Brauner , Carlos Llamas Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, netdev@vger.kernel.org, Alice Ryhl Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable To generate netlink frames from Rust code easily, generate Rust libraries with methods for generating different netlink messages as appropriate. The new 'rust' type corresponds to a Rust version of the C target 'kernel'. There is no Rust version of the 'uapi' target since Rust code exports its uapi via C headers - choice of language is opaque to userspace. This logic is kept in the existing ynl_gen_c.py file to reuse CodeWriter and other shared pieces of logic in the existing python file. This has the disadvantage that the gen_c part of the name is now wrong, as it also generates Rust. One possible solution to this could be to rename the file. Signed-off-by: Alice Ryhl --- tools/net/ynl/pyynl/ynl_gen_c.py | 139 +++++++++++++++++++++++++++++++++++= +++- tools/net/ynl/ynl-regen.sh | 2 +- 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen= _c.py index 0e1e486c1185..76b8b2f1ac16 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -19,6 +19,7 @@ import pathlib import os import re import shutil +import subprocess import sys import tempfile import yaml as pyyaml @@ -1744,6 +1745,19 @@ class CodeWriter: else: self.p('}' + line) =20 + def array_start(self, line=3D''): + if line: + line =3D line + ' ' + self.p(line + '[') + self._ind +=3D 1 + + def array_end(self, line=3D''): + if line and line[0] not in {';', ','}: + line =3D ' ' + line + self._ind -=3D 1 + self._nl =3D False + self.p(']' + line) + def write_doc_line(self, doc, indent=3DTrue): words =3D doc.split() line =3D ' *' @@ -3415,10 +3429,126 @@ def find_kernel_root(full_path): return full_path, sub_path[:-1] =20 =20 +def render_rust(family, cw): + cw.p('#![allow(unreachable_pub, clippy::wrong_self_convention)]') + cw.p('use kernel::netlink::{Family, MulticastGroup};') + cw.p('use kernel::prelude::*;') + cw.nl() + + family_upper =3D c_upper(family.ident_name) + family_name =3D f'{family_upper}_NL_FAMILY' + mcgrps_name =3D f'{family_name}_MCGRPS' + + cw.p(f'pub static {family_name}: Family =3D Family::const_new(') + cw._ind +=3D 1 + cw.p('&crate::THIS_MODULE,') + cw.p(f'kernel::uapi::{family.fam_key},') + cw.p(f'kernel::uapi::{family.ver_key},') + if family.mcgrps['list']: + cw.p(f'&{mcgrps_name},') + else: + cw.p('&[],') + cw._ind -=3D 1 + cw.p(');') + cw.nl() + + if family.mcgrps['list']: + cw.array_start(f'static {mcgrps_name}: [MulticastGroup; {len(famil= y.mcgrps["list"])}] =3D ') + for grp in family.mcgrps['list']: + cw.p(f'MulticastGroup::const_new(c"{grp["name"]}"),') + cw.array_end(';') + cw.nl() + + for idx, (op_name, op) in enumerate(item for item in family.msgs.items= () if 'event' in item[1]): + struct_name =3D op_name.capitalize() + + if 'doc' in op: + doc_lines =3D op['doc'].strip().split('\n') + for line in doc_lines: + cw.p(f'/// {line.strip()}') + + cw.block_start(f'pub struct {struct_name}') + cw.p('skb: kernel::netlink::GenlMsg,') + cw.block_end() + cw.nl() + + cw.block_start(f'impl {struct_name}') + cw.p('/// Create a new multicast message.') + cw.p('pub fn new(') + cw._ind +=3D 1 + cw.p('size: usize,') + cw.p('portid: u32,') + cw.p('seq: u32,') + cw.p('flags: kernel::alloc::Flags,') + cw._ind -=3D 1 + cw.block_start(') -> Result') + cw.p(f'const {op.enum_name}: u8 =3D kernel::uapi::{op.enum_name} a= s u8;') + cw.p('let skb =3D kernel::netlink::NetlinkSkBuff::new(size, flags)= ?;') + cw.p(f'let skb =3D skb.genlmsg_put(portid, seq, &{family_name}, {o= p.enum_name})?;') + cw.p('Ok(Self { skb })') + cw.block_end() + cw.nl() + + grp_idx =3D 0 + if 'mcgrp' in op: + grp_idx =3D next(i for i, grp in enumerate(family.mcgrps['list= ']) if grp['name'] =3D=3D op['mcgrp']) + + cw.p('/// Broadcast this message.') + cw.block_start('pub fn multicast(self, portid: u32, flags: kernel:= :alloc::Flags) -> Result') + cw.p(f'self.skb.multicast(&{family_name}, portid, {grp_idx}, flags= )') + cw.block_end() + cw.nl() + + cw.p('/// Check if this message type has listeners.') + cw.block_start('pub fn has_listeners() -> bool') + cw.p(f'{family_name}.has_listeners({grp_idx})') + cw.block_end() + + attr_set_name =3D op['attribute-set'] + attr_set =3D family.attr_sets[attr_set_name] + event_attrs =3D op['event']['attributes'] + + for attr_name in event_attrs: + attr =3D attr_set[attr_name] + method_name =3D attr_name.replace('-', '_') + + if attr.type =3D=3D 'u32': + put_fn =3D 'put_u32' + arg_str =3D ', val' + method_args =3D '(&mut self, val: u32)' + elif attr.type =3D=3D 'string': + put_fn =3D 'put_string' + arg_str =3D ', val' + method_args =3D '(&mut self, val: &CStr)' + elif attr.type =3D=3D 'flag': + put_fn =3D 'put_flag' + arg_str =3D '' + method_args =3D '(&mut self)' + else: + put_fn =3D f'put_{attr.type}' + arg_str =3D ', val' + method_args =3D f'(&mut self, val: {attr.type})' + + cw.nl() + if 'doc' in attr.yaml: + doc_lines =3D attr.yaml['doc'].strip().split('\n') + for line in doc_lines: + cw.p(f'/// {line.strip()}') + + cw.block_start(f'pub fn {method_name}{method_args} -> Result') + cw.p(f'const {attr.enum_name}: c_int =3D kernel::uapi::{attr.e= num_name} as c_int;') + cw.p(f'self.skb.{put_fn}({attr.enum_name}{arg_str})') + cw.block_end() + + cw.block_end() + cw.nl() + cw.p(' ') + + def main(): parser =3D argparse.ArgumentParser(description=3D'Netlink simple parsi= ng generator') parser.add_argument('--mode', dest=3D'mode', type=3Dstr, required=3DTr= ue, - choices=3D('user', 'kernel', 'uapi')) + choices=3D('user', 'kernel', 'uapi', 'rust')) parser.add_argument('--spec', dest=3D'spec', type=3Dstr, required=3DTr= ue) parser.add_argument('--header', dest=3D'header', action=3D'store_true'= , default=3DNone) parser.add_argument('--source', dest=3D'header', action=3D'store_false= ') @@ -3471,6 +3601,13 @@ def main(): render_uapi(parsed, cw) return =20 + if args.mode =3D=3D 'rust': + render_rust(parsed, cw) + cw.close_out_file() + if args.out_file: + subprocess.run(['rustfmt', '--edition', '2021', args.out_file]) + return + hdr_prot =3D f"_LINUX_{parsed.c_name.upper()}_GEN_H" if args.header: cw.p('#ifndef ' + hdr_prot) diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index d9809276db98..4f5ceb4fe147 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -17,7 +17,7 @@ done KDIR=3D$(dirname $(dirname $(dirname $(dirname $(realpath $0))))) pushd ${search:-$KDIR} >>/dev/null =20 -files=3D$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user= \)') +files=3D$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user= \|rust\)') for f in $files; do # params: 0 1 2 3 # $YAML YNL-GEN kernel $mode --=20 2.54.0.rc0.605.g598a273b03-goog From nobody Tue Jun 16 02:34:53 2026 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3077833DED9 for ; Wed, 15 Apr 2026 09:39:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245985; cv=none; b=XMfyUDAv5p111Pj3ydl4wR4A43pCt0NFRqlsnxPmkbcg0A26apiqbSe13AvBEZPaq8jmTWUxj7e/VBwJUAoIpXs8DazqudxYFFFUj8KJz+sN1qcVSW1oRD5kYuKQWi849t4tzBaWYOmCJXR8qFZaklwc/Ma8lKoZovAwdr+RTxY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245985; c=relaxed/simple; bh=zNZrVUvlUUacK2uhATRh2O/ldEh8gnA9RA9Mdle7mFI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Dagk4Z1yMetIORz5wx3xBoY7CcZG1xkXnZeji6N2+hUqnwF8tUjZu0oWKZcOp2RBd3rN8KzCGlvCvXb0UUqMq/CUrfOoWo0npsr/Lx/qKVc3TfrOHKQNG1IujhjbKnuh0XChXDKcxOZls23CiPI737Kbu14rVoy+9SN68cTqRCs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=XDPTJzs0; arc=none smtp.client-ip=209.85.221.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="XDPTJzs0" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-43d14a4bcd0so6997837f8f.3 for ; Wed, 15 Apr 2026 02:39:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1776245977; x=1776850777; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=e/MVTcJFkC+EYfL8l2u+nLk94ROweihpl1VmTbmUq7w=; b=XDPTJzs0VPWtBjbB9jwwajszc4Af8Vd7TOABt+xZ3z43sKRBWYSm7kWGaqz41JxwT6 5lt4kkVlMiWPJRzBdyQ3pQPdb3jnmVEXisro8OItyLGuskB962p9S5MTynwywgH4Ton4 cxzK3gTk3ejwl7uG/0l1ferWao0M9wSqrqv3tFiWKdMVHlzbG42oWLh76/8pfwZXHm16 +RzaGkmhzVCxpZvJY1tkiHdJk1qdjr/sY5Y2fTgM7C0x9pgmsAYqjgE9Vk5mTSYO5uwX WeES8aVDpFKA95H+5/UkavhuKMT5+m803ext/VdNXygm9+jmtxMPy1jkmFvRcgK+WBrA 8Jqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776245977; x=1776850777; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=e/MVTcJFkC+EYfL8l2u+nLk94ROweihpl1VmTbmUq7w=; b=UHv1iVr+/KC6UQs5WRLKvL7ewoZA/h32Y5mUZE0zb5CJBI0EtDsDGlFY+ktQD2hupX 2nah+H1F1iWKcuwAR60/E2RFCF5PQwfRAd53wo9EGdCkPCcnv8LF95FBvCEGi571lggu CEjrOPlU+tVGnpD6nfzf7dMCW2oSJlgnQv42g+M7E4tFIYeQORuvvGbDMX01lsAxz/PI FLavnDOELWqsRW0rA8YH86LB0ALoZNUq6lspDiKaJW6WEbiPJTPQ582345zdT+ymk6G4 xjQ38tztXdzTbG5MEuiPuQk9xhU13yrqaMeBDSZzqPUbFmAsiDElxedM+cvvJGUWt5GT Mm3Q== X-Gm-Message-State: AOJu0YwzELdQdU5v/nxvA2bgN6CSWCzII4QP7n0ab/Q/h7ARfaKNcxUY zpeJWEUN/GWhbNY3p52rXrmC1TtAvQGWwO3Uk8frJgNOWsPi+YcBDps+2IwZj65Xe5rInMNuoig riGYFdBBgTECHKtJMog== X-Received: from wmqn6.prod.google.com ([2002:a05:600c:4f86:b0:488:ad14:4c60]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:19cd:b0:485:17a7:b9c7 with SMTP id 5b1f17b1804b1-488d67e3671mr285545145e9.10.1776245977384; Wed, 15 Apr 2026 02:39:37 -0700 (PDT) Date: Wed, 15 Apr 2026 09:37:53 +0000 In-Reply-To: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=7776; i=aliceryhl@google.com; h=from:subject:message-id; bh=zNZrVUvlUUacK2uhATRh2O/ldEh8gnA9RA9Mdle7mFI=; b=owEBbQKS/ZANAwAKAQRYvu5YxjlGAcsmYgBp31zOpb/X3H5KVDxnJg+z0/8mY1syUfppmoDEq vAW+PS1vPmJAjMEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCad9czgAKCRAEWL7uWMY5 RtVxD/4j/wFrXmCUB1T1DC3Tqoa4xOWS6oAYUqUzfs53UibmR5Gab7kQbI3h3jrF37RDv5uTZtK zSDJuj8MwIRDVW7o9uka9IJ/+cZmzBfM9PlXb7PqE2/xmPXZ53gXZmMcOMERM8vbxea6fBNL1av HVEqWiBGfqTMFUIr4bQCkrScf09/ELayO23vg4JBMzNx3OEyxfbMfo/YIncIBO0V4C9jgdtHF5m 4rVolRp1dUT82q6iIT6v+NBS13o8PP2P6dsxiGObjrcdoKIG48j/s/BFD32iwWtI/4LnazSCFAy P+xj2P3+9d4RQOXCMhy/4COtfyG5SCit0cH14y0+r9l5E2S7CA4D6SSKLDCfSCv702LmzGOLasP gPdEqhGFTnNt7piP0qDVlEB8s000FVz3pZsnVuC1/B9V+VlVXV+1dD2X0wEkT5YD90+emTZmIMc JKFj7BZJssbD8aF7VOmx3dXrxTXfmClM2v3a0F2hV0sJREY3COxbHdz9e3WREch0uze6ZMG4VJq VWQGanK079F8yS3y7eM94m413BWXtCC0f4+25hkrRJjwvaW7EGee2wid1BeKI6Be6SPOUA7vMAu feeJhtn8VRIFN6PYJsCTVG1W2J5OHjO6DC3KiV2byPkOCSxfTLr5uK3Rd3Y5pLn3nKcRYJ7CzRE pnoRhozCv3AOAPQ== X-Mailer: b4 0.14.3 Message-ID: <20260415-binder-netlink-v3-3-84be9ba63ee2@google.com> Subject: [PATCH v3 3/4] rust_binder: add generated netlink.rs file From: Alice Ryhl To: Miguel Ojeda , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Donald Hunter , Jakub Kicinski , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Christian Brauner , Carlos Llamas Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, netdev@vger.kernel.org, Alice Ryhl Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable To use netlink from Rust Binder, add a new generated netlink file using the new script and Documentation/netlink/specs/binder.yaml. Signed-off-by: Alice Ryhl --- drivers/android/Kconfig | 2 +- drivers/android/binder/netlink.rs | 113 +++++++++++++++++++++++++= ++++ drivers/android/binder/rust_binder_main.rs | 9 ++- rust/uapi/uapi_helper.h | 1 + 4 files changed, 122 insertions(+), 3 deletions(-) diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index e2e402c9d175..606a9d07f774 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -16,7 +16,7 @@ config ANDROID_BINDER_IPC =20 config ANDROID_BINDER_IPC_RUST bool "Rust version of Android Binder IPC Driver" - depends on RUST && MMU && !ANDROID_BINDER_IPC + depends on RUST && MMU && NET && !ANDROID_BINDER_IPC help This enables the Rust implementation of the Binder driver. =20 diff --git a/drivers/android/binder/netlink.rs b/drivers/android/binder/net= link.rs new file mode 100644 index 000000000000..2a842c7b1b33 --- /dev/null +++ b/drivers/android/binder/netlink.rs @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/binder.yaml */ +/* YNL-GEN rust source */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#![allow(unreachable_pub, clippy::wrong_self_convention)] +use kernel::netlink::{Family, MulticastGroup}; +use kernel::prelude::*; + +pub static BINDER_NL_FAMILY: Family =3D Family::const_new( + &crate::THIS_MODULE, + kernel::uapi::BINDER_FAMILY_NAME, + kernel::uapi::BINDER_FAMILY_VERSION, + &BINDER_NL_FAMILY_MCGRPS, +); + +static BINDER_NL_FAMILY_MCGRPS: [MulticastGroup; 1] =3D [MulticastGroup::c= onst_new(c"report")]; + +/// A multicast event sent to userspace subscribers to notify them about +/// binder transaction failures. The generated report provides the full +/// details of the specific transaction that failed. The intention is for +/// programs to monitor these events and react to the failures as needed. +pub struct Report { + skb: kernel::netlink::GenlMsg, +} + +impl Report { + /// Create a new multicast message. + pub fn new( + size: usize, + portid: u32, + seq: u32, + flags: kernel::alloc::Flags, + ) -> Result { + const BINDER_CMD_REPORT: u8 =3D kernel::uapi::BINDER_CMD_REPORT as= u8; + let skb =3D kernel::netlink::NetlinkSkBuff::new(size, flags)?; + let skb =3D skb.genlmsg_put(portid, seq, &BINDER_NL_FAMILY, BINDER= _CMD_REPORT)?; + Ok(Self { skb }) + } + + /// Broadcast this message. + pub fn multicast(self, portid: u32, flags: kernel::alloc::Flags) -> Re= sult { + self.skb.multicast(&BINDER_NL_FAMILY, portid, 0, flags) + } + + /// Check if this message type has listeners. + pub fn has_listeners() -> bool { + BINDER_NL_FAMILY.has_listeners(0) + } + + /// The enum binder_driver_return_protocol returned to the sender. + pub fn error(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_ERROR: c_int =3D kernel::uapi::BINDER_A_REPO= RT_ERROR as c_int; + self.skb.put_u32(BINDER_A_REPORT_ERROR, val) + } + + /// The binder context where the transaction occurred. + pub fn context(&mut self, val: &CStr) -> Result { + const BINDER_A_REPORT_CONTEXT: c_int =3D kernel::uapi::BINDER_A_RE= PORT_CONTEXT as c_int; + self.skb.put_string(BINDER_A_REPORT_CONTEXT, val) + } + + /// The PID of the sender process. + pub fn from_pid(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_FROM_PID: c_int =3D kernel::uapi::BINDER_A_R= EPORT_FROM_PID as c_int; + self.skb.put_u32(BINDER_A_REPORT_FROM_PID, val) + } + + /// The TID of the sender thread. + pub fn from_tid(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_FROM_TID: c_int =3D kernel::uapi::BINDER_A_R= EPORT_FROM_TID as c_int; + self.skb.put_u32(BINDER_A_REPORT_FROM_TID, val) + } + + /// The PID of the recipient process. This attribute may not be present + /// if the target could not be determined. + pub fn to_pid(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_TO_PID: c_int =3D kernel::uapi::BINDER_A_REP= ORT_TO_PID as c_int; + self.skb.put_u32(BINDER_A_REPORT_TO_PID, val) + } + + /// The TID of the recipient thread. This attribute may not be present + /// if the target could not be determined. + pub fn to_tid(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_TO_TID: c_int =3D kernel::uapi::BINDER_A_REP= ORT_TO_TID as c_int; + self.skb.put_u32(BINDER_A_REPORT_TO_TID, val) + } + + /// When present, indicates the failed transaction is a reply. + pub fn is_reply(&mut self) -> Result { + const BINDER_A_REPORT_IS_REPLY: c_int =3D kernel::uapi::BINDER_A_R= EPORT_IS_REPLY as c_int; + self.skb.put_flag(BINDER_A_REPORT_IS_REPLY) + } + + /// The bitmask of enum transaction_flags from the transaction. + pub fn flags(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_FLAGS: c_int =3D kernel::uapi::BINDER_A_REPO= RT_FLAGS as c_int; + self.skb.put_u32(BINDER_A_REPORT_FLAGS, val) + } + + /// The application-defined code from the transaction. + pub fn code(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_CODE: c_int =3D kernel::uapi::BINDER_A_REPOR= T_CODE as c_int; + self.skb.put_u32(BINDER_A_REPORT_CODE, val) + } + + /// The transaction payload size in bytes. + pub fn data_size(&mut self, val: u32) -> Result { + const BINDER_A_REPORT_DATA_SIZE: c_int =3D kernel::uapi::BINDER_A_= REPORT_DATA_SIZE as c_int; + self.skb.put_u32(BINDER_A_REPORT_DATA_SIZE, val) + } +} diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/b= inder/rust_binder_main.rs index 678e987902aa..9057e5dba7ed 100644 --- a/drivers/android/binder/rust_binder_main.rs +++ b/drivers/android/binder/rust_binder_main.rs @@ -36,6 +36,8 @@ mod deferred_close; mod defs; mod error; +#[allow(dead_code)] +mod netlink; mod node; mod page_range; mod process; @@ -286,19 +288,22 @@ fn ptr_align(value: usize) -> Option { // SAFETY: We call register in `init`. static BINDER_SHRINKER: Shrinker =3D unsafe { Shrinker::new() }; =20 -struct BinderModule {} +struct BinderModule { + _netlink: kernel::netlink::Registration, +} =20 impl kernel::Module for BinderModule { fn init(_module: &'static kernel::ThisModule) -> Result { // SAFETY: The module initializer never runs twice, so we only cal= l this once. unsafe { crate::context::CONTEXTS.init() }; =20 + let netlink =3D crate::netlink::BINDER_NL_FAMILY.register()?; BINDER_SHRINKER.register(c"android-binder")?; =20 // SAFETY: The module is being loaded, so we can initialize binder= fs. unsafe { kernel::error::to_result(binderfs::init_rust_binderfs())?= }; =20 - Ok(Self {}) + Ok(Self { _netlink: netlink }) } } =20 diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h index 06d7d1a2e8da..86c7b6b284b0 100644 --- a/rust/uapi/uapi_helper.h +++ b/rust/uapi/uapi_helper.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include --=20 2.54.0.rc0.605.g598a273b03-goog From nobody Tue Jun 16 02:34:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 20A4333B95A for ; Wed, 15 Apr 2026 09:39:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245983; cv=none; b=hGcb955esST6LssDcCv3Tla5aj3eaDmzIfjeIPqUz7mofgl+xDyq+olZAVtiR8U1X313TZAUgvSpKIxg447x6lG5tbkAXm81P8HLO3Os16JUgoWLG5kVsc4bTHOpZoo706qFy7xh8ajWLmJo+LJxRbNb6Mp5xyrrxSAfz1DgzFQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776245983; c=relaxed/simple; bh=vfGvEyjIXVQjJQSlbIVj7pBLzMyBjbJ+t2zP8GbMnR8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=CNXTsJvuXqpuijNTfCbNbbYGiU/ckibvYV5lBAFzt+7JWw6hZvtg+F+cXKha7eG1AKogEJJb24f3LCk/fqHfNoZvSVkMg6NsS965xEJptgu+sgYPL+S/MNndcSSnN1fRQcrbOFsPcYvmoQTiEMGRyKnXduQyZzNPVDYMKl6QbDw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=OBizY9Bu; arc=none smtp.client-ip=209.85.208.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--aliceryhl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="OBizY9Bu" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-66c165a7a8cso5558762a12.1 for ; Wed, 15 Apr 2026 02:39:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1776245979; x=1776850779; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=KCLsNX3cjUHeEq5VeNxpgUoLu/D96PUreoTUzfquF0E=; b=OBizY9BuFTecC3VlcVrrQOUhekdFFP/+Oq4Vth58Ez3n1QxBdkOV2P0UVSZgrdDhMn Jgnmyvt1AfrV3Dhk68d8EG4Xkm4SO/gIOph0r3kTgwCLrx/PTNA+iWKP7mmegQvJ2nON +Ut6xA3EDYdnH4k3UFD/maFlzQ8T5F+kd94gyx0QO81kpeMvzoEzywLvpPm3FwTLRK1A r92JZIFFqvz7WEQT5AU+EOJG9n8kH9uAwIj/NC3fPb+oHRZfEbZcRPcrNGqvTOurKN0D AMoK79Z9yRD1pi91M7LrwCVzbz+CUkB0xKWDxQH2+zohUT53slbftSgwR52+m/oR6plG U9Ww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776245979; x=1776850779; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=KCLsNX3cjUHeEq5VeNxpgUoLu/D96PUreoTUzfquF0E=; b=N0xBswJb30ANFvCmSlXzAK6ir9wnxvO/sPdXtcCliGBPgDivp6pHcJwcRNjalhVaXt 3QoqrcjteS65unIkh/Q3iRu7SrUAvoLhb9hzgU82+oAc31EmWYsq6p9QN0vA5MdbbcAL 6Vp9CttSn17vagtSSIkah3utGweWsR5WCycVnIkKuqh5j0np4+621O+VcCYu/j3dpbgW fH+l+WxlHpdnfFTtLQfAqCqNpE0s78M5SkifJ3RtNj3a2ZNwAKloTDD+gee7ljZTxdzY OW8ouRGQ30KGyqPhTKZDD7Tzt4wyrFvxZTj06cFXWf5MN7ij0cSClW+Y4NYYf3LBQ4Md yfTg== X-Gm-Message-State: AOJu0YzGC9u5BPd4UcMGGfCdxc8wyUSO7GBFd76YGOZhwc+rM5nLXzm+ AEt4TSVkFxpqA5xBTJ0LxTAA9M2S7XL3mWCZyiCc8IsYdcaHKK6Dqe3fiaDdOt2HhQEtQX68shJ gKhS/f2KDLvApggsBPQ== X-Received: from edcy21.prod.google.com ([2002:a05:6402:3595:b0:66e:6991:c7ce]) (user=aliceryhl job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:13c4:b0:66e:4372:7518 with SMTP id 4fb4d7f45d1cf-670786a9b2bmr10483508a12.2.1776245979186; Wed, 15 Apr 2026 02:39:39 -0700 (PDT) Date: Wed, 15 Apr 2026 09:37:54 +0000 In-Reply-To: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260415-binder-netlink-v3-0-84be9ba63ee2@google.com> X-Developer-Key: i=aliceryhl@google.com; a=openpgp; fpr=49F6C1FAA74960F43A5B86A1EE7A392FDE96209F X-Developer-Signature: v=1; a=openpgp-sha256; l=4356; i=aliceryhl@google.com; h=from:subject:message-id; bh=FfVP1wsykDG+Hqd6UNsmQSo/Ch7AeRVTR4IJAZiaXEk=; b=owEBbAKT/ZANAwAKAQRYvu5YxjlGAcsmYgBp31zOfKasmwbfkCFFGYk82gVJITP2uU11raptY z9wiVal5LmJAjIEAAEKAB0WIQSDkqKUTWQHCvFIvbIEWL7uWMY5RgUCad9czgAKCRAEWL7uWMY5 RsahD/joS8/bdiDdrB6f/uSSvZiTtI6Tp6QeRXhgNBIobGYX0Qj4hFIdb7NUK89L3JA2gBQnwWr Ffwp3lnsuxybXMktZ7nRl96Z+o5F24WOYHsPXm17YMIk/BsJIzdhzUqYhxnq4SZI9tdQ5azczgt o89dmvlyoGmaRjoMGycdfCho4CNjPRhmYht85chyQrBjKgAozFgGSVhsKyVG7US6hTVKRVAOFNM 1xGYBOSkW8qnZv+8xcdo42+kZiCopu+QfXI0ARTbEDT+dcBR27jRtFIbzQBT4p2v5AejEXhrboE tHs6dFEP/CPJymx7jCUIc7dAIHTENYmoMD1/pvyb1JME7mVaN97QWm7CNrcFy+ucPmZjv87bURG qMRIuXCKcm6DuSMp1Hxk2JS+FOLmP9bCXpH3E1/zuPQbc20bbiIiw7BaHfX7xttma1mxnEYMhv3 FLLmBI3RsQqVq3NkSpzz+2iaSEXwFGIR1EutrxMDeg9VnoM2IVpj7I4c0YYt58hgC/FFY0l1bGI 32c44Iu8VlKdOGJw6K/NNxebqd3zSrLbeTDj0IBDvaTwEU8a/B/lmjCQkoQue+M9VxRmBGyp/uy fUdUuyal/xKRakn/bQMJt6yVSt/0zV5UjF1T1BJmS0q6U7Qzx6lwWWzOZWfZrc8Gw7Na8VEzGhz boMqCgh/zE+Xv X-Mailer: b4 0.14.3 Message-ID: <20260415-binder-netlink-v3-4-84be9ba63ee2@google.com> Subject: [PATCH v3 4/4] rust_binder: report netlink transactions From: Alice Ryhl To: Miguel Ojeda , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Trevor Gross , Danilo Krummrich , Donald Hunter , Jakub Kicinski , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Greg Kroah-Hartman , "=?utf-8?q?Arve_Hj=C3=B8nnev=C3=A5g?=" , Todd Kjos , Christian Brauner , Carlos Llamas Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, netdev@vger.kernel.org, Alice Ryhl Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Carlos Llamas The Android Binder driver supports a netlink API that reports transaction *failures* to a userapce daemon. This allows devices to monitor processes with many failed transactions so that it can e.g. kill misbehaving apps. One very important thing that this monitors is when many oneway messages are sent to a frozen process, so there is special handling to ensure this scenario is surfaced over netlink. Signed-off-by: Carlos Llamas Signed-off-by: Alice Ryhl --- drivers/android/binder/rust_binder_main.rs | 1 - drivers/android/binder/thread.rs | 10 ++++++++ drivers/android/binder/transaction.rs | 40 ++++++++++++++++++++++++++= ++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/b= inder/rust_binder_main.rs index 9057e5dba7ed..407cda7bd766 100644 --- a/drivers/android/binder/rust_binder_main.rs +++ b/drivers/android/binder/rust_binder_main.rs @@ -36,7 +36,6 @@ mod deferred_close; mod defs; mod error; -#[allow(dead_code)] mod netlink; mod node; mod page_range; diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thre= ad.rs index 97d5f31e8fe3..aa4e93a877ac 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -1263,6 +1263,15 @@ fn transaction(self: &Arc, cmd: u32, reader: &= mut UserSliceReader) -> Resu } } =20 + if info.oneway_spam_suspect { + // If this is both a oneway spam suspect and a failure, we rep= ort it twice. This is + // useful in case the transaction failed with BR_TRANSACTION_P= ENDING_FROZEN. + info.report_netlink(BR_ONEWAY_SPAM_SUSPECT, &self.process.ctx); + } + if info.reply !=3D 0 { + info.report_netlink(info.reply, &self.process.ctx); + } + Ok(()) } =20 @@ -1332,6 +1341,7 @@ fn reply_inner(self: &Arc, info: &mut Transacti= onInfo) -> BinderResult { ); let reply =3D Err(BR_FAILED_REPLY); orig.from.deliver_reply(reply, &orig); + info.reply =3D BR_FAILED_REPLY; err.reply =3D BR_TRANSACTION_COMPLETE; err }); diff --git a/drivers/android/binder/transaction.rs b/drivers/android/binder= /transaction.rs index 47d5e4d88b07..3fa7091ed8a6 100644 --- a/drivers/android/binder/transaction.rs +++ b/drivers/android/binder/transaction.rs @@ -3,6 +3,7 @@ // Copyright (C) 2025 Google LLC. =20 use kernel::{ + netlink::GENLMSG_DEFAULT_SIZE, prelude::*, seq_file::SeqFile, seq_print, @@ -17,6 +18,7 @@ allocation::{Allocation, TranslatedFds}, defs::*, error::{BinderError, BinderResult}, + netlink::Report, node::{Node, NodeRef}, process::{Process, ProcessInner}, ptr_align, @@ -49,6 +51,44 @@ impl TransactionInfo { pub(crate) fn is_oneway(&self) -> bool { self.flags & TF_ONE_WAY !=3D 0 } + + pub(crate) fn report_netlink(&self, reply: u32, ctx: &crate::Context) { + if let Err(err) =3D self.report_netlink_inner(reply, ctx) { + pr_warn!( + "{}:{} netlink report failed: {err:?}\n", + self.from_pid, + self.from_tid + ); + } + } + + fn report_netlink_inner(&self, reply: u32, ctx: &crate::Context) -> ke= rnel::error::Result { + if !Report::has_listeners() { + return Ok(()); + } + let mut report =3D Report::new(GENLMSG_DEFAULT_SIZE, 0, 0, GFP_KER= NEL)?; + + report.error(reply)?; + report.context(&ctx.name)?; + report.from_pid(self.from_pid as u32)?; + report.from_tid(self.from_tid as u32)?; + if self.to_pid !=3D 0 { + report.to_pid(self.to_pid as u32)?; + } + if self.to_tid !=3D 0 { + report.to_tid(self.to_tid as u32)?; + } + + if self.is_reply { + report.is_reply()?; + } + report.flags(self.flags)?; + report.code(self.code)?; + report.data_size(self.data_size as u32)?; + + report.multicast(0, GFP_KERNEL)?; + Ok(()) + } } =20 use core::mem::offset_of; --=20 2.54.0.rc0.605.g598a273b03-goog