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