* [PATCH 1/2] rust: add synchronous message digest support [not found] <20230515043353.2324288-1-tomo@exabit.dev> @ 2023-05-15 4:34 ` FUJITA Tomonori 2023-05-15 6:11 ` Kent Overstreet 2023-05-16 5:52 ` Eric Biggers 2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori 1 sibling, 2 replies; 10+ messages in thread From: FUJITA Tomonori @ 2023-05-15 4:34 UTC (permalink / raw) To: rust-for-linux, netdev, linux-crypto; +Cc: FUJITA Tomonori From: FUJITA Tomonori <fujita.tomonori@gmail•com> Adds abstractions for crypto shash. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> --- rust/bindings/bindings_helper.h | 1 + rust/helpers.c | 24 +++++++ rust/kernel/crypto.rs | 108 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 4 files changed, 135 insertions(+) create mode 100644 rust/kernel/crypto.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 50e7a76d5455..65683b9aa45d 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -6,6 +6,7 @@ * Sorted alphabetically. */ +#include <crypto/hash.h> #include <linux/slab.h> #include <linux/refcount.h> #include <linux/wait.h> diff --git a/rust/helpers.c b/rust/helpers.c index 81e80261d597..03c131b1ca38 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -18,6 +18,7 @@ * accidentally exposed. */ +#include <crypto/hash.h> #include <linux/bug.h> #include <linux/build_bug.h> #include <linux/err.h> @@ -27,6 +28,29 @@ #include <linux/sched/signal.h> #include <linux/wait.h> +void rust_helper_crypto_free_shash(struct crypto_shash *tfm) +{ + crypto_free_shash(tfm); +} +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash); + +unsigned int rust_helper_crypto_shash_digestsize(struct crypto_shash *tfm) +{ + return crypto_shash_digestsize(tfm); +} +EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_digestsize); + +unsigned int rust_helper_crypto_shash_descsize(struct crypto_shash *tfm) +{ + return crypto_shash_descsize(tfm); +} +EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_descsize); + +int rust_helper_crypto_shash_init(struct shash_desc *desc) { + return crypto_shash_init(desc); +} +EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_init); + __noreturn void rust_helper_BUG(void) { BUG(); diff --git a/rust/kernel/crypto.rs b/rust/kernel/crypto.rs new file mode 100644 index 000000000000..963487428525 --- /dev/null +++ b/rust/kernel/crypto.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Cryptography. +//! +//! C headers: [`include/crypto/hash.h`](../../../../include/crypto/hash.h) + +use crate::{ + error::{from_err_ptr, to_result, Result}, + str::CStr, +}; +use alloc::alloc::{alloc, dealloc}; +use core::alloc::Layout; + +/// Represents `struct crypto_shash *`. +/// +/// # Invariants +/// +/// The pointer is valid. +pub struct Shash(*mut bindings::crypto_shash); + +impl Drop for Shash { + fn drop(&mut self) { + // SAFETY: The type invariant guarantees that the pointer is valid. + unsafe { bindings::crypto_free_shash(self.0) } + } +} + +impl Shash { + /// Creates a [`Shash`] object for a message digest handle. + pub fn new(name: &'static CStr, t: u32, mask: u32) -> Result<Shash> { + // SAFETY: FFI call. + let ptr = + unsafe { from_err_ptr(bindings::crypto_alloc_shash(name.as_char_ptr(), t, mask)) }?; + Ok(Self(ptr)) + } + + /// Sets optional key used by the hashing algorithm. + pub fn setkey(&mut self, data: &[u8]) -> Result { + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { + bindings::crypto_shash_setkey(self.0, data.as_ptr(), data.len() as u32) + }) + } + + /// Returns the size of the result of the transformation. + pub fn digestsize(&self) -> u32 { + // SAFETY: The type invariant guarantees that the pointer is valid. + unsafe { bindings::crypto_shash_digestsize(self.0) } + } +} + +/// Represents `struct shash_desc *`. +/// +/// # Invariants +/// +/// The field `ptr` is non-null and valid for the lifetime of the object. +pub struct ShashDesc<'a> { + ptr: *mut bindings::shash_desc, + tfm: &'a Shash, + size: usize, +} + +impl Drop for ShashDesc<'_> { + fn drop(&mut self) { + // SAFETY: The type invariant guarantees that the pointer is valid. + unsafe { + dealloc( + self.ptr.cast(), + Layout::from_size_align(self.size, 2).unwrap(), + ); + } + } +} + +impl<'a> ShashDesc<'a> { + /// Creates a [`ShashDesc`] object for a request data structure for message digest. + pub fn new(tfm: &'a Shash) -> Result<Self> { + // SAFETY: The type invariant guarantees that the pointer is valid. + let size = core::mem::size_of::<bindings::shash_desc>() + + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize; + let layout = Layout::from_size_align(size, 2)?; + let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc; + let mut desc = ShashDesc { ptr, tfm, size }; + // SAFETY: The `desc.tfm` is non-null and valid for the lifetime of this object. + unsafe { (*desc.ptr).tfm = desc.tfm.0 }; + Ok(desc) + } + + /// (Re)initializes message digest. + pub fn init(&mut self) -> Result { + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { bindings::crypto_shash_init(self.ptr) }) + } + + /// Adds data to message digest for processing. + pub fn update(&mut self, data: &[u8]) -> Result { + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { + bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32) + }) + } + + /// Calculates message digest. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) }) + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 676995d4e460..753fd62b84f1 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -35,6 +35,8 @@ extern crate self as kernel; #[cfg(not(testlib))] mod allocator; mod build_assert; +#[cfg(CONFIG_CRYPTO)] +pub mod crypto; pub mod error; pub mod init; pub mod ioctl; -- 2.34.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] rust: add synchronous message digest support 2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori @ 2023-05-15 6:11 ` Kent Overstreet 2023-05-16 5:52 ` Eric Biggers 1 sibling, 0 replies; 10+ messages in thread From: Kent Overstreet @ 2023-05-15 6:11 UTC (permalink / raw) To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori On Mon, May 15, 2023 at 04:34:27AM +0000, FUJITA Tomonori wrote: > From: FUJITA Tomonori <fujita.tomonori@gmail•com> > > Adds abstractions for crypto shash. > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> > --- > rust/bindings/bindings_helper.h | 1 + > rust/helpers.c | 24 +++++++ > rust/kernel/crypto.rs | 108 ++++++++++++++++++++++++++++++++ > rust/kernel/lib.rs | 2 + I think in the long run we're going to need Rust bindings located right next to the .c files they're wrapping. Certainly modules will. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] rust: add synchronous message digest support 2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori 2023-05-15 6:11 ` Kent Overstreet @ 2023-05-16 5:52 ` Eric Biggers 2023-05-16 8:25 ` FUJITA Tomonori 1 sibling, 1 reply; 10+ messages in thread From: Eric Biggers @ 2023-05-16 5:52 UTC (permalink / raw) To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori Hi Fujita, On Mon, May 15, 2023 at 04:34:27AM +0000, FUJITA Tomonori wrote: > diff --git a/rust/helpers.c b/rust/helpers.c > index 81e80261d597..03c131b1ca38 100644 > --- a/rust/helpers.c > +++ b/rust/helpers.c > @@ -18,6 +18,7 @@ > * accidentally exposed. > */ > > +#include <crypto/hash.h> > #include <linux/bug.h> > #include <linux/build_bug.h> > #include <linux/err.h> > @@ -27,6 +28,29 @@ > #include <linux/sched/signal.h> > #include <linux/wait.h> > > +void rust_helper_crypto_free_shash(struct crypto_shash *tfm) > +{ > + crypto_free_shash(tfm); > +} > +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash); Shouldn't this code be compiled only when the crypto API is available? > +impl<'a> ShashDesc<'a> { > + /// Creates a [`ShashDesc`] object for a request data structure for message digest. > + pub fn new(tfm: &'a Shash) -> Result<Self> { > + // SAFETY: The type invariant guarantees that the pointer is valid. > + let size = core::mem::size_of::<bindings::shash_desc>() > + + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize; > + let layout = Layout::from_size_align(size, 2)?; > + let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc; > + let mut desc = ShashDesc { ptr, tfm, size }; > + // SAFETY: The `desc.tfm` is non-null and valid for the lifetime of this object. > + unsafe { (*desc.ptr).tfm = desc.tfm.0 }; > + Ok(desc) > + } > + > + /// (Re)initializes message digest. > + pub fn init(&mut self) -> Result { > + // SAFETY: The type invariant guarantees that the pointer is valid. > + to_result(unsafe { bindings::crypto_shash_init(self.ptr) }) > + } > + > + /// Adds data to message digest for processing. > + pub fn update(&mut self, data: &[u8]) -> Result { > + // SAFETY: The type invariant guarantees that the pointer is valid. > + to_result(unsafe { > + bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32) > + }) > + } > + > + /// Calculates message digest. > + pub fn finalize(&mut self, output: &mut [u8]) -> Result { > + // SAFETY: The type invariant guarantees that the pointer is valid. > + to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) }) > + } This doesn't enforce that init() is called before update() or finalize(). I think that needs to be checked in the Rust code, since the C code doesn't have defined behavior in that case. - Eric ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] rust: add synchronous message digest support 2023-05-16 5:52 ` Eric Biggers @ 2023-05-16 8:25 ` FUJITA Tomonori 0 siblings, 0 replies; 10+ messages in thread From: FUJITA Tomonori @ 2023-05-16 8:25 UTC (permalink / raw) To: ebiggers; +Cc: tomo, rust-for-linux, netdev, linux-crypto, fujita.tomonori Hi, On Mon, 15 May 2023 22:52:19 -0700 Eric Biggers <ebiggers@kernel•org> wrote: >> +#include <crypto/hash.h> >> #include <linux/bug.h> >> #include <linux/build_bug.h> >> #include <linux/err.h> >> @@ -27,6 +28,29 @@ >> #include <linux/sched/signal.h> >> #include <linux/wait.h> >> >> +void rust_helper_crypto_free_shash(struct crypto_shash *tfm) >> +{ >> + crypto_free_shash(tfm); >> +} >> +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash); > > Shouldn't this code be compiled only when the crypto API is available? Oops, I'll add #ifdef CONFIG_CRYPTO >> +impl<'a> ShashDesc<'a> { >> + /// Creates a [`ShashDesc`] object for a request data structure for message digest. >> + pub fn new(tfm: &'a Shash) -> Result<Self> { >> + // SAFETY: The type invariant guarantees that the pointer is valid. >> + let size = core::mem::size_of::<bindings::shash_desc>() >> + + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize; >> + let layout = Layout::from_size_align(size, 2)?; >> + let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc; >> + let mut desc = ShashDesc { ptr, tfm, size }; >> + // SAFETY: The `desc.tfm` is non-null and valid for the lifetime of this object. >> + unsafe { (*desc.ptr).tfm = desc.tfm.0 }; >> + Ok(desc) >> + } >> + >> + /// (Re)initializes message digest. >> + pub fn init(&mut self) -> Result { >> + // SAFETY: The type invariant guarantees that the pointer is valid. >> + to_result(unsafe { bindings::crypto_shash_init(self.ptr) }) >> + } >> + >> + /// Adds data to message digest for processing. >> + pub fn update(&mut self, data: &[u8]) -> Result { >> + // SAFETY: The type invariant guarantees that the pointer is valid. >> + to_result(unsafe { >> + bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32) >> + }) >> + } >> + >> + /// Calculates message digest. >> + pub fn finalize(&mut self, output: &mut [u8]) -> Result { >> + // SAFETY: The type invariant guarantees that the pointer is valid. >> + to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) }) >> + } > > This doesn't enforce that init() is called before update() or finalize(). I > think that needs to be checked in the Rust code, since the C code doesn't have > defined behavior in that case. Surely, Rust side should handle the case. If the new() function internally calls init() before returning, it works? The new() returns an initialized ShaDesc object. Thanks for reviewing! ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/2] rust: add socket support [not found] <20230515043353.2324288-1-tomo@exabit.dev> 2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori @ 2023-05-15 4:34 ` FUJITA Tomonori 2023-05-15 14:14 ` Andrew Lunn 2023-05-16 17:08 ` Wedson Almeida Filho 1 sibling, 2 replies; 10+ messages in thread From: FUJITA Tomonori @ 2023-05-15 4:34 UTC (permalink / raw) To: rust-for-linux, netdev, linux-crypto; +Cc: FUJITA Tomonori From: FUJITA Tomonori <fujita.tomonori@gmail•com> minimum abstraction for networking. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> --- rust/bindings/bindings_helper.h | 3 + rust/kernel/lib.rs | 2 + rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 rust/kernel/net.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 65683b9aa45d..7cbb5dd96bf6 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -7,8 +7,11 @@ */ #include <crypto/hash.h> +#include <linux/net.h> #include <linux/slab.h> #include <linux/refcount.h> +#include <linux/socket.h> +#include <linux/tcp.h> #include <linux/wait.h> #include <linux/sched.h> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 753fd62b84f1..42dbef3d9e88 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -40,6 +40,8 @@ pub mod crypto; pub mod error; pub mod init; pub mod ioctl; +#[cfg(CONFIG_NET)] +pub mod net; pub mod prelude; pub mod print; mod static_assert; diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs new file mode 100644 index 000000000000..204b5222abdc --- /dev/null +++ b/rust/kernel/net.rs @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Networking. +//! +//! C headers: [`include/linux/net.h`](../../../../include/linux/net.h), +//! [`include/linux/socket.h`](../../../../include/linux/socket.h), + +use crate::{ + bindings, + error::{to_result, Result}, +}; +use alloc::vec::Vec; + +/// Represents `struct socket *`. +/// +/// # Invariants +/// +/// The pointer is valid. +pub struct Socket { + pub(crate) sock: *mut bindings::socket, +} + +impl Drop for Socket { + fn drop(&mut self) { + // SAFETY: The type invariant guarantees that the pointer is valid. + unsafe { bindings::sock_release(self.sock) } + } +} + +/// Address families. Defines AF_* here. +pub enum Family { + /// Internet IP Protocol. + Ip = bindings::AF_INET as isize, +} + +/// Communication type. +pub enum SocketType { + /// Stream (connection). + Stream = bindings::sock_type_SOCK_STREAM as isize, +} + +/// Protocols. +pub enum Protocol { + /// Transmission Control Protocol. + Tcp = bindings::IPPROTO_TCP as isize, +} + +impl Socket { + /// Creates a [`Socket`] object. + pub fn new(family: Family, sf: SocketType, proto: Protocol) -> Result<Self> { + let mut sock = core::ptr::null_mut(); + + // SAFETY: FFI call. + to_result(unsafe { + bindings::sock_create_kern( + &mut bindings::init_net, + family as _, + sf as _, + proto as _, + &mut sock, + ) + }) + .map(|_| Socket { sock }) + } + + /// Moves a socket to listening state. + pub fn listen(&mut self, backlog: i32) -> Result { + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { bindings::kernel_listen(self.sock, backlog) }) + } + + /// Binds an address to a socket. + pub fn bind(&mut self, addr: &SocketAddr) -> Result { + let (addr, addrlen) = match addr { + SocketAddr::V4(addr) => ( + addr as *const _ as _, + core::mem::size_of::<bindings::sockaddr>() as i32, + ), + }; + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { bindings::kernel_bind(self.sock, addr, addrlen) }) + } + + /// Accepts a connection + pub fn accept(&mut self) -> Result<Self> { + let mut client = core::ptr::null_mut(); + // SAFETY: The type invariant guarantees that the pointer is valid. + to_result(unsafe { bindings::kernel_accept(self.sock, &mut client, 0) }) + .map(|_| Socket { sock: client }) + } + + /// Receives a message from a socket. + pub fn recvmsg(&mut self, bufs: &mut [&mut [u8]], flags: i32) -> Result<usize> { + let mut msg = bindings::msghdr::default(); + let mut kvec = Vec::try_with_capacity(bufs.len())?; + let mut len = 0; + for i in 0..bufs.len() { + len += bufs[i].len(); + kvec.try_push(bindings::kvec { + iov_base: bufs[i].as_mut_ptr().cast(), + iov_len: bufs[i].len(), + })?; + } + // SAFETY: The type invariant guarantees that the pointer is valid. + let r = unsafe { + bindings::kernel_recvmsg( + self.sock, + &mut msg, + kvec.as_mut_ptr(), + bufs.len(), + len, + flags, + ) + }; + to_result(r).map(|_| r as usize) + } + + /// Sends a message through a socket. + pub fn sendmsg(&mut self, bufs: &[&[u8]]) -> Result<usize> { + let mut msg = bindings::msghdr::default(); + let mut kvec = Vec::try_with_capacity(bufs.len())?; + let mut len = 0; + for i in 0..bufs.len() { + len += bufs[i].len(); + kvec.try_push(bindings::kvec { + iov_base: bufs[i].as_ptr() as *mut u8 as _, + iov_len: bufs[i].len(), + })?; + } + // SAFETY: The type invariant guarantees that the pointer is valid. + let r = unsafe { + bindings::kernel_sendmsg(self.sock, &mut msg, kvec.as_mut_ptr(), bufs.len(), len) + }; + to_result(r).map(|_| r as usize) + } +} + +/// A socket address. +pub enum SocketAddr { + /// An IPv4 socket address. + V4(SocketAddrV4), +} + +/// Represents `struct in_addr`. +#[repr(transparent)] +pub struct Ipv4Addr(bindings::in_addr); + +impl Ipv4Addr { + /// Creates a new IPv4 address from four eight-bit octets. + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self { + Self(bindings::in_addr { + s_addr: u32::from_be_bytes([a, b, c, d]).to_be(), + }) + } +} + +/// Prepresents `struct sockaddr_in`. +#[repr(transparent)] +pub struct SocketAddrV4(bindings::sockaddr_in); + +impl SocketAddrV4 { + /// Creates a new IPv4 socket address. + pub const fn new(addr: Ipv4Addr, port: u16) -> Self { + Self(bindings::sockaddr_in { + sin_family: Family::Ip as _, + sin_port: port.to_be(), + sin_addr: addr.0, + __pad: [0; 8], + }) + } +} + +/// Waits for a full request +pub const MSG_WAITALL: i32 = bindings::MSG_WAITALL as i32; -- 2.34.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support 2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori @ 2023-05-15 14:14 ` Andrew Lunn 2023-05-16 5:43 ` FUJITA Tomonori 2023-05-16 17:08 ` Wedson Almeida Filho 1 sibling, 1 reply; 10+ messages in thread From: Andrew Lunn @ 2023-05-15 14:14 UTC (permalink / raw) To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori On Mon, May 15, 2023 at 04:34:28AM +0000, FUJITA Tomonori wrote: > From: FUJITA Tomonori <fujita.tomonori@gmail•com> > > minimum abstraction for networking. > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> > --- > rust/bindings/bindings_helper.h | 3 + > rust/kernel/lib.rs | 2 + > rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++ The full networking API is huge. So trying to put it all into net.rs is unlikely to work in the long run. Maybe it would be better to name this file based on the tiny little bit of the network API you are writing an abstraction for? If i'm reading the code correctly, you are abstracting the in kernel socket API for only TCP over IPv4. Probably with time that will get extended to IPv6, and then UDP. So maybe call this net-kern-socket.rs? Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support 2023-05-15 14:14 ` Andrew Lunn @ 2023-05-16 5:43 ` FUJITA Tomonori 2023-05-16 12:07 ` Andrew Lunn 0 siblings, 1 reply; 10+ messages in thread From: FUJITA Tomonori @ 2023-05-16 5:43 UTC (permalink / raw) To: andrew; +Cc: tomo, rust-for-linux, netdev, linux-crypto, fujita.tomonori On Mon, 15 May 2023 16:14:56 +0200 Andrew Lunn <andrew@lunn•ch> wrote: > On Mon, May 15, 2023 at 04:34:28AM +0000, FUJITA Tomonori wrote: >> From: FUJITA Tomonori <fujita.tomonori@gmail•com> >> >> minimum abstraction for networking. > >> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> >> --- >> rust/bindings/bindings_helper.h | 3 + >> rust/kernel/lib.rs | 2 + >> rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++ > > The full networking API is huge. So trying to put it all into net.rs > is unlikely to work in the long run. Maybe it would be better to name > this file based on the tiny little bit of the network API you are > writing an abstraction for? Yeah, in the long run. I tried the simplest but if the maintainers prefer that approach as the first step, I'll update the patch. how about rust/net/socket.rs ? > If i'm reading the code correctly, you are abstracting the in kernel > socket API for only TCP over IPv4. Probably with time that will get > extended to IPv6, and then UDP. So maybe call this net-kern-socket.rs? Yes. It's thin abstraction, just wrapping socket APIs. So it's easy to extend it for IPv6, non IP protocols, etc. Thanks, ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support 2023-05-16 5:43 ` FUJITA Tomonori @ 2023-05-16 12:07 ` Andrew Lunn 0 siblings, 0 replies; 10+ messages in thread From: Andrew Lunn @ 2023-05-16 12:07 UTC (permalink / raw) To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, fujita.tomonori On Tue, May 16, 2023 at 05:43:21AM +0000, FUJITA Tomonori wrote: > On Mon, 15 May 2023 16:14:56 +0200 > Andrew Lunn <andrew@lunn•ch> wrote: > > > On Mon, May 15, 2023 at 04:34:28AM +0000, FUJITA Tomonori wrote: > >> From: FUJITA Tomonori <fujita.tomonori@gmail•com> > >> > >> minimum abstraction for networking. > > > >> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> > >> --- > >> rust/bindings/bindings_helper.h | 3 + > >> rust/kernel/lib.rs | 2 + > >> rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++ > > > > The full networking API is huge. So trying to put it all into net.rs > > is unlikely to work in the long run. Maybe it would be better to name > > this file based on the tiny little bit of the network API you are > > writing an abstraction for? > > Yeah, in the long run. I tried the simplest but if the maintainers > prefer that approach as the first step, I'll update the patch. how > about rust/net/socket.rs ? That is better. But probably Eric or one of the other core maintainers should comment. I also put kern into the name to try to make it clear that this is not the BSD Socket kAPI, but the kernel internal API for sockets. I don't know how important this distinction is. Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support 2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori 2023-05-15 14:14 ` Andrew Lunn @ 2023-05-16 17:08 ` Wedson Almeida Filho 2023-05-17 2:46 ` FUJITA Tomonori 1 sibling, 1 reply; 10+ messages in thread From: Wedson Almeida Filho @ 2023-05-16 17:08 UTC (permalink / raw) To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori On Mon, 15 May 2023 at 02:45, FUJITA Tomonori <tomo@exabit•dev> wrote: > > From: FUJITA Tomonori <fujita.tomonori@gmail•com> > > minimum abstraction for networking. > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail•com> > --- > rust/bindings/bindings_helper.h | 3 + > rust/kernel/lib.rs | 2 + > rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++ > 3 files changed, 179 insertions(+) > create mode 100644 rust/kernel/net.rs Fujita, thanks for this. We have basic networking support in the `rust` branch. In fact, we also have support for async networking in there as well. For example, the 9p server uses it. At the moment we're prioritizing upstreaming the pieces for which we have projects waiting. Do you have an _actual_ user in mind for this? In any case, let's please start with that instead of a brand-new reimplementation. Cheers, -Wedson > diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h > index 65683b9aa45d..7cbb5dd96bf6 100644 > --- a/rust/bindings/bindings_helper.h > +++ b/rust/bindings/bindings_helper.h > @@ -7,8 +7,11 @@ > */ > > #include <crypto/hash.h> > +#include <linux/net.h> > #include <linux/slab.h> > #include <linux/refcount.h> > +#include <linux/socket.h> > +#include <linux/tcp.h> > #include <linux/wait.h> > #include <linux/sched.h> > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index 753fd62b84f1..42dbef3d9e88 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -40,6 +40,8 @@ pub mod crypto; > pub mod error; > pub mod init; > pub mod ioctl; > +#[cfg(CONFIG_NET)] > +pub mod net; > pub mod prelude; > pub mod print; > mod static_assert; > diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs > new file mode 100644 > index 000000000000..204b5222abdc > --- /dev/null > +++ b/rust/kernel/net.rs > @@ -0,0 +1,174 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! Networking. > +//! > +//! C headers: [`include/linux/net.h`](../../../../include/linux/net.h), > +//! [`include/linux/socket.h`](../../../../include/linux/socket.h), > + > +use crate::{ > + bindings, > + error::{to_result, Result}, > +}; > +use alloc::vec::Vec; > + > +/// Represents `struct socket *`. > +/// > +/// # Invariants > +/// > +/// The pointer is valid. > +pub struct Socket { > + pub(crate) sock: *mut bindings::socket, > +} > + > +impl Drop for Socket { > + fn drop(&mut self) { > + // SAFETY: The type invariant guarantees that the pointer is valid. > + unsafe { bindings::sock_release(self.sock) } > + } > +} > + > +/// Address families. Defines AF_* here. > +pub enum Family { > + /// Internet IP Protocol. > + Ip = bindings::AF_INET as isize, > +} > + > +/// Communication type. > +pub enum SocketType { > + /// Stream (connection). > + Stream = bindings::sock_type_SOCK_STREAM as isize, > +} > + > +/// Protocols. > +pub enum Protocol { > + /// Transmission Control Protocol. > + Tcp = bindings::IPPROTO_TCP as isize, > +} > + > +impl Socket { > + /// Creates a [`Socket`] object. > + pub fn new(family: Family, sf: SocketType, proto: Protocol) -> Result<Self> { > + let mut sock = core::ptr::null_mut(); > + > + // SAFETY: FFI call. > + to_result(unsafe { > + bindings::sock_create_kern( > + &mut bindings::init_net, > + family as _, > + sf as _, > + proto as _, > + &mut sock, > + ) > + }) > + .map(|_| Socket { sock }) > + } > + > + /// Moves a socket to listening state. > + pub fn listen(&mut self, backlog: i32) -> Result { > + // SAFETY: The type invariant guarantees that the pointer is valid. > + to_result(unsafe { bindings::kernel_listen(self.sock, backlog) }) > + } > + > + /// Binds an address to a socket. > + pub fn bind(&mut self, addr: &SocketAddr) -> Result { > + let (addr, addrlen) = match addr { > + SocketAddr::V4(addr) => ( > + addr as *const _ as _, > + core::mem::size_of::<bindings::sockaddr>() as i32, > + ), > + }; > + // SAFETY: The type invariant guarantees that the pointer is valid. > + to_result(unsafe { bindings::kernel_bind(self.sock, addr, addrlen) }) > + } > + > + /// Accepts a connection > + pub fn accept(&mut self) -> Result<Self> { > + let mut client = core::ptr::null_mut(); > + // SAFETY: The type invariant guarantees that the pointer is valid. > + to_result(unsafe { bindings::kernel_accept(self.sock, &mut client, 0) }) > + .map(|_| Socket { sock: client }) > + } > + > + /// Receives a message from a socket. > + pub fn recvmsg(&mut self, bufs: &mut [&mut [u8]], flags: i32) -> Result<usize> { > + let mut msg = bindings::msghdr::default(); > + let mut kvec = Vec::try_with_capacity(bufs.len())?; > + let mut len = 0; > + for i in 0..bufs.len() { > + len += bufs[i].len(); > + kvec.try_push(bindings::kvec { > + iov_base: bufs[i].as_mut_ptr().cast(), > + iov_len: bufs[i].len(), > + })?; > + } > + // SAFETY: The type invariant guarantees that the pointer is valid. > + let r = unsafe { > + bindings::kernel_recvmsg( > + self.sock, > + &mut msg, > + kvec.as_mut_ptr(), > + bufs.len(), > + len, > + flags, > + ) > + }; > + to_result(r).map(|_| r as usize) > + } > + > + /// Sends a message through a socket. > + pub fn sendmsg(&mut self, bufs: &[&[u8]]) -> Result<usize> { > + let mut msg = bindings::msghdr::default(); > + let mut kvec = Vec::try_with_capacity(bufs.len())?; > + let mut len = 0; > + for i in 0..bufs.len() { > + len += bufs[i].len(); > + kvec.try_push(bindings::kvec { > + iov_base: bufs[i].as_ptr() as *mut u8 as _, > + iov_len: bufs[i].len(), > + })?; > + } > + // SAFETY: The type invariant guarantees that the pointer is valid. > + let r = unsafe { > + bindings::kernel_sendmsg(self.sock, &mut msg, kvec.as_mut_ptr(), bufs.len(), len) > + }; > + to_result(r).map(|_| r as usize) > + } > +} > + > +/// A socket address. > +pub enum SocketAddr { > + /// An IPv4 socket address. > + V4(SocketAddrV4), > +} > + > +/// Represents `struct in_addr`. > +#[repr(transparent)] > +pub struct Ipv4Addr(bindings::in_addr); > + > +impl Ipv4Addr { > + /// Creates a new IPv4 address from four eight-bit octets. > + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self { > + Self(bindings::in_addr { > + s_addr: u32::from_be_bytes([a, b, c, d]).to_be(), > + }) > + } > +} > + > +/// Prepresents `struct sockaddr_in`. > +#[repr(transparent)] > +pub struct SocketAddrV4(bindings::sockaddr_in); > + > +impl SocketAddrV4 { > + /// Creates a new IPv4 socket address. > + pub const fn new(addr: Ipv4Addr, port: u16) -> Self { > + Self(bindings::sockaddr_in { > + sin_family: Family::Ip as _, > + sin_port: port.to_be(), > + sin_addr: addr.0, > + __pad: [0; 8], > + }) > + } > +} > + > +/// Waits for a full request > +pub const MSG_WAITALL: i32 = bindings::MSG_WAITALL as i32; > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support 2023-05-16 17:08 ` Wedson Almeida Filho @ 2023-05-17 2:46 ` FUJITA Tomonori 0 siblings, 0 replies; 10+ messages in thread From: FUJITA Tomonori @ 2023-05-17 2:46 UTC (permalink / raw) To: wedsonaf; +Cc: tomo, rust-for-linux, netdev, linux-crypto, fujita.tomonori Hi, On Tue, 16 May 2023 14:08:47 -0300 Wedson Almeida Filho <wedsonaf@gmail•com> wrote: > We have basic networking support in the `rust` branch. In fact, we > also have support for async networking in there as well. For example, > the 9p server uses it. > > At the moment we're prioritizing upstreaming the pieces for which we > have projects waiting. Do you have an _actual_ user in mind for this? I've implemented in-kernel TLS 1.3 handshake on the top of this. https://github.com/fujita/rust-tls The in-kernel TLS handshake feature is controversial. Proposals were rejected in the past. So I like to know the opinions of subsystem maintainers early, implementing in-kernel security-relevant code in Rust could change the situation. The requirement for networking is simple, read/write with a vector and setsockopt. So I submitted minimum abstractions. > In any case, let's please start with that instead of a brand-new > reimplementation. Sure, if netdev maintainers could merge Rust abstractions for networking soon, I'll rework on this. But I don't think there is much overlap between this and rust branch. Even if we could have abstractions specific for TCP like TcpListener and TcpStream, we still need thin abstractions for socket because there are several use-cases of non IP sockets, I think. Thanks, ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-05-17 3:05 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20230515043353.2324288-1-tomo@exabit.dev>
2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori
2023-05-15 6:11 ` Kent Overstreet
2023-05-16 5:52 ` Eric Biggers
2023-05-16 8:25 ` FUJITA Tomonori
2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori
2023-05-15 14:14 ` Andrew Lunn
2023-05-16 5:43 ` FUJITA Tomonori
2023-05-16 12:07 ` Andrew Lunn
2023-05-16 17:08 ` Wedson Almeida Filho
2023-05-17 2:46 ` FUJITA Tomonori
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox