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