xref: /linux/rust/kernel/net/netlink.rs (revision ff9b465ddb95d7842282998348df88ff55f62c4a)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2026 Google LLC.
4 
5 //! Rust support for generic netlink.
6 //!
7 //! Currently only supports exposing multicast groups.
8 //!
9 //! C header: [`include/net/genetlink.h`](srctree/include/net/genetlink.h)
10 
11 use kernel::{
12     alloc::{self, AllocError},
13     error::to_result,
14     num::casts::u16_as_usize,
15     prelude::*,
16     transmute::AsBytes,
17     types::Opaque,
18     ThisModule,
19 };
20 
21 use core::{
22     mem::ManuallyDrop,
23     ptr::NonNull, //
24 };
25 
26 /// The default netlink message size.
27 pub const GENLMSG_DEFAULT_SIZE: usize = bindings::GENLMSG_DEFAULT_SIZE;
28 
29 /// A wrapper around `struct sk_buff` for generic netlink messages.
30 ///
31 /// This type is intended to be specific for buffers used with netlink only, and other usecases for
32 /// `struct sk_buff` are out-of-scope for this abstraction.
33 ///
34 /// # Invariants
35 ///
36 /// The pointer has ownership over a valid `sk_buff`.
37 pub struct NetlinkSkBuff {
38     skb: NonNull<kernel::bindings::sk_buff>,
39 }
40 
41 impl NetlinkSkBuff {
42     /// Creates a new `NetlinkSkBuff` with the given size.
43     pub fn new(size: usize, flags: alloc::Flags) -> Result<NetlinkSkBuff, AllocError> {
44         // SAFETY: `genlmsg_new` only requires its arguments to be valid integers.
45         let skb = unsafe { bindings::genlmsg_new(size, flags.as_raw()) };
46         let skb = NonNull::new(skb).ok_or(AllocError)?;
47         Ok(NetlinkSkBuff { skb })
48     }
49 
50     /// Puts a generic netlink header into the `NetlinkSkBuff`.
51     pub fn genlmsg_put(
52         self,
53         portid: u32,
54         seq: u32,
55         family: &'static Family,
56         cmd: u8,
57     ) -> Result<GenlMsg, AllocError> {
58         let skb = self.skb.as_ptr();
59         // SAFETY: The skb and family pointers are valid.
60         let hdr = unsafe { bindings::genlmsg_put(skb, portid, seq, family.as_raw(), 0, cmd) };
61         let hdr = NonNull::new(hdr).ok_or(AllocError)?;
62         Ok(GenlMsg { skb: self, hdr })
63     }
64 }
65 
66 impl Drop for NetlinkSkBuff {
67     fn drop(&mut self) {
68         // SAFETY: We have ownership over the `sk_buff`, so we may free it.
69         unsafe { bindings::nlmsg_free(self.skb.as_ptr()) }
70     }
71 }
72 
73 /// A generic netlink message being constructed.
74 ///
75 /// # Invariants
76 ///
77 /// `hdr` references the header in this netlink message.
78 pub struct GenlMsg {
79     skb: NetlinkSkBuff,
80     hdr: NonNull<c_void>,
81 }
82 
83 impl GenlMsg {
84     /// Puts an attribute into the message.
85     #[inline]
86     fn put<T>(&mut self, attrtype: c_int, value: &T) -> Result
87     where
88         T: ?Sized + AsBytes,
89     {
90         // `nla_len` is a 16-bit field that encodes the total attribute length
91         // (header + payload). Subtracting the header size from `u16::MAX` gives
92         // the largest payload that still fits within that field.
93         const MAX_PAYLOAD_LEN: usize = u16_as_usize(u16::MAX) - size_of::<bindings::nlattr>();
94 
95         let skb = self.skb.skb.as_ptr();
96         let len = size_of_val(value);
97         let ptr = core::ptr::from_ref(value).cast::<c_void>();
98         if len > MAX_PAYLOAD_LEN {
99             return Err(EMSGSIZE);
100         }
101         // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and the provided value is
102         // readable and initialized for its `size_of` bytes.
103         to_result(unsafe { bindings::nla_put(skb, attrtype, len as c_int, ptr) })
104     }
105 
106     /// Puts a `u32` attribute into the message.
107     #[inline]
108     pub fn put_u32(&mut self, attrtype: c_int, value: u32) -> Result {
109         self.put(attrtype, &value)
110     }
111 
112     /// Puts a string attribute into the message.
113     #[inline]
114     pub fn put_string(&mut self, attrtype: c_int, value: &CStr) -> Result {
115         self.put(attrtype, value.to_bytes_with_nul())
116     }
117 
118     /// Puts a flag attribute into the message.
119     #[inline]
120     pub fn put_flag(&mut self, attrtype: c_int) -> Result {
121         let skb = self.skb.skb.as_ptr();
122         // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and a null pointer is valid
123         // when the length is zero.
124         to_result(unsafe { bindings::nla_put(skb, attrtype, 0, core::ptr::null()) })
125     }
126 
127     /// Sends the generic netlink message as a multicast message.
128     #[inline]
129     pub fn multicast(
130         self,
131         family: &'static Family,
132         portid: u32,
133         group: u32,
134         flags: alloc::Flags,
135     ) -> Result {
136         let me = ManuallyDrop::new(self);
137         // SAFETY: The `skb` and `family` pointers are valid. We pass ownership of the `skb` to
138         // `genlmsg_multicast` by not dropping `self`.
139         unsafe {
140             bindings::genlmsg_end(me.skb.skb.as_ptr(), me.hdr.as_ptr());
141             to_result(bindings::genlmsg_multicast(
142                 family.as_raw(),
143                 me.skb.skb.as_ptr(),
144                 portid,
145                 group,
146                 flags.as_raw(),
147             ))
148         }
149     }
150 }
151 impl Drop for GenlMsg {
152     fn drop(&mut self) {
153         // SAFETY: The `hdr` pointer references the header of this generic netlink message.
154         unsafe { bindings::genlmsg_cancel(self.skb.skb.as_ptr(), self.hdr.as_ptr()) };
155     }
156 }
157 
158 /// Flags for a generic netlink family.
159 struct FamilyFlags {
160     /// Whether the family supports network namespaces.
161     netnsok: bool,
162     /// Whether the family supports parallel operations.
163     parallel_ops: bool,
164 }
165 
166 impl FamilyFlags {
167     /// Converts the flags to the bitfield representation used by `genl_family`.
168     const fn into_bitfield(self) -> bindings::__BindgenBitfieldUnit<[u8; 1]> {
169         // The below shifts are verified correct by test_family_flags_bitfield() below.
170         //
171         // Although bindgen generates helpers to change bitfields based on the C headers, these
172         // helpers unfortunately can't be used in const context. Since `Family` needs to be filled
173         // out at build-time, we use this helper instead.
174         let mut bits = 0;
175         if self.netnsok {
176             bits |= 1 << 0;
177         }
178         if self.parallel_ops {
179             bits |= 1 << 1;
180         }
181         // Convert from little endian to the target's endianness.
182         bits = u8::from_le(bits);
183         // SAFETY: This bitfield is represented as an u8.
184         unsafe { core::mem::transmute::<u8, bindings::__BindgenBitfieldUnit<[u8; 1]>>(bits) }
185     }
186 }
187 
188 /// A generic netlink family.
189 #[repr(transparent)]
190 pub struct Family {
191     inner: Opaque<bindings::genl_family>,
192 }
193 
194 // SAFETY: The `Family` type is thread safe.
195 unsafe impl Sync for Family {}
196 
197 impl Family {
198     /// Creates a new `Family` instance.
199     ///
200     /// Intended to be used from const context only. Will panic if provided with invalid arguments.
201     ///
202     /// The name must be a nul-terminated string, but it is taken as `&[u8]` so that it can be used
203     /// more conveniently with the strings generated by bindgen.
204     pub const fn const_new(
205         module: &ThisModule,
206         name: &[u8],
207         version: u32,
208         mcgrps: &'static [MulticastGroup],
209     ) -> Family {
210         let n_mcgrps = mcgrps.len() as u8;
211         if n_mcgrps as usize != mcgrps.len() {
212             panic!("too many mcgrps");
213         }
214         let mut genl_family = bindings::genl_family {
215             version,
216             _bitfield_1: FamilyFlags {
217                 netnsok: true,
218                 parallel_ops: true,
219             }
220             .into_bitfield(),
221             module: module.as_ptr(),
222             mcgrps: mcgrps.as_ptr().cast(),
223             n_mcgrps,
224             ..pin_init::zeroed()
225         };
226         if CStr::from_bytes_with_nul(name).is_err() {
227             panic!("genl_family name not nul-terminated");
228         }
229         if genl_family.name.len() < name.len() {
230             panic!("genl_family name too long");
231         }
232         let mut i = 0;
233         while i < name.len() {
234             genl_family.name[i] = name[i];
235             i += 1;
236         }
237         Family {
238             inner: Opaque::new(genl_family),
239         }
240     }
241 
242     /// Checks if there are any listeners for the given multicast group.
243     pub fn has_listeners(&self, group: u32) -> bool {
244         // SAFETY: The family and init_net pointers are valid.
245         unsafe {
246             bindings::genl_has_listeners(self.as_raw(), &raw mut bindings::init_net, group) != 0
247         }
248     }
249 
250     /// Returns a raw pointer to the underlying `genl_family` structure.
251     pub fn as_raw(&self) -> *mut bindings::genl_family {
252         self.inner.get()
253     }
254 }
255 
256 /// A generic netlink multicast group.
257 #[repr(transparent)]
258 pub struct MulticastGroup {
259     // No Opaque because fully immutable
260     group: bindings::genl_multicast_group,
261 }
262 
263 // SAFETY: Pure data so thread safe.
264 unsafe impl Sync for MulticastGroup {}
265 
266 impl MulticastGroup {
267     /// Creates a new `MulticastGroup` instance.
268     ///
269     /// Intended to be used from const context only. Will panic if provided with invalid arguments.
270     pub const fn const_new(name: &CStr) -> MulticastGroup {
271         let mut group: bindings::genl_multicast_group = pin_init::zeroed();
272 
273         let name = name.to_bytes_with_nul();
274         if group.name.len() < name.len() {
275             panic!("genl_multicast_group name too long");
276         }
277         let mut i = 0;
278         while i < name.len() {
279             group.name[i] = name[i];
280             i += 1;
281         }
282 
283         MulticastGroup { group }
284     }
285 }
286 
287 /// A registration of a generic netlink family.
288 ///
289 /// This type represents the registration of a [`Family`]. When an instance of this type is
290 /// dropped, its respective generic netlink family will be unregistered from the system.
291 ///
292 /// # Invariants
293 ///
294 /// `self.family` always holds a valid reference to an initialized and registered [`Family`].
295 pub struct Registration {
296     family: &'static Family,
297 }
298 
299 impl Family {
300     /// Registers the generic netlink family with the kernel.
301     pub fn register(&'static self) -> Result<Registration> {
302         // SAFETY: `self.as_raw()` is a valid pointer to a `genl_family` struct.
303         // The `genl_family` struct is static, so it will outlive the registration.
304         to_result(unsafe { bindings::genl_register_family(self.as_raw()) })?;
305         Ok(Registration { family: self })
306     }
307 }
308 
309 impl Drop for Registration {
310     fn drop(&mut self) {
311         // SAFETY: `self.family.as_raw()` is a valid pointer to a registered `genl_family` struct.
312         // The `Registration` struct ensures that `genl_unregister_family` is called exactly once
313         // for this family when it goes out of scope.
314         unsafe { bindings::genl_unregister_family(self.family.as_raw()) };
315     }
316 }
317 
318 #[macros::kunit_tests(rust_netlink)]
319 mod tests {
320     use super::*;
321 
322     #[test]
323     fn test_family_flags_bitfield() {
324         for netnsok in [false, true] {
325             for parallel_ops in [false, true] {
326                 let mut b_fam = bindings::genl_family {
327                     ..Default::default()
328                 };
329                 b_fam.set_netnsok(if netnsok { 1 } else { 0 });
330                 b_fam.set_parallel_ops(if parallel_ops { 1 } else { 0 });
331 
332                 let c_bitfield = FamilyFlags {
333                     netnsok,
334                     parallel_ops,
335                 }
336                 .into_bitfield();
337 
338                 // SAFETY: The bit field is stored as u8.
339                 let b_val: u8 = unsafe { core::mem::transmute(b_fam._bitfield_1) };
340                 // SAFETY: The bit field is stored as u8.
341                 let c_val: u8 = unsafe { core::mem::transmute(c_bitfield) };
342                 assert_eq!(b_val, c_val);
343             }
344         }
345     }
346 }
347