All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] Rust Socket abstractions
@ 2023-08-14  9:22 Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 1/7] rust: net: add net module files and shared enums Michele Dalle Rive
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:22 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

This patch series is intended to create Rust abstractions for Sockets
and other fundamental network entities. 

Specifically, it was added:
- Ip address and Socket address wrappers (for `in_addr`, `in6_addr`,
  `sockaddr_in`, `sockaddr_in6`, `sockaddr_storage`).
- Socket wrapper.
- Socket flags and options enums.
- TCP and UDP specific abstractions over the Rust Socket structure.

This series is a RFC because I would appreciate some feedback about:
- The structure of the module: is the division of the files and modules
  appropriate or should it be more or less fine-grained?
  Also, should the `net` module export all the structures of its
  submodules? I noticed that it is done in the standard library.
- Whether the documentation is comprehensive enough.
- A few other specific questions, written in the individual patches.

I would greatly appreciate any kind of feedback or opinion. 
I am pretty new to the patch/mailing list world, so please point out any
mistake I might make.

The changes in this patch series are based on top of the latest commit
of `rust-next` in the Rust git tree: 
19cd7b5d229c ("btf, scripts: rust: drop is_rust_module.sh")

Michele Dalle Rive (7):
  rust: net: add net module files and shared enums.
  rust: net: add ip and socket address bindings.
  rust: net: add socket-related flags and flagset.
  rust: net: add socket wrapper.
  rust: net: implement socket options API.
  rust: net: add socket TCP wrappers.
  rust: net: add socket UDP wrappers.

 rust/bindings/bindings_helper.h |    3 +
 rust/kernel/lib.rs              |    2 +
 rust/kernel/net.rs              |  185 +++++
 rust/kernel/net/addr.rs         | 1215 ++++++++++++++++++++++++++++++
 rust/kernel/net/ip.rs           |   73 ++
 rust/kernel/net/socket.rs       |  641 ++++++++++++++++
 rust/kernel/net/socket/flags.rs |  467 ++++++++++++
 rust/kernel/net/socket/opts.rs  | 1222 +++++++++++++++++++++++++++++++
 rust/kernel/net/tcp.rs          |  252 +++++++
 rust/kernel/net/udp.rs          |  182 +++++
 10 files changed, 4242 insertions(+)
 create mode 100644 rust/kernel/net.rs
 create mode 100644 rust/kernel/net/addr.rs
 create mode 100644 rust/kernel/net/ip.rs
 create mode 100644 rust/kernel/net/socket.rs
 create mode 100644 rust/kernel/net/socket/flags.rs
 create mode 100644 rust/kernel/net/socket/opts.rs
 create mode 100644 rust/kernel/net/tcp.rs
 create mode 100644 rust/kernel/net/udp.rs

-- 
2.41.0


^ permalink raw reply	[flat|nested] 26+ messages in thread

* [RFC PATCH 1/7] rust: net: add net module files and shared enums.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
@ 2023-08-14  9:22 ` Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 2/7] rust: net: add ip and socket address bindings Michele Dalle Rive
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:22 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Create `net` module files and network headers in `bindings_helper.h`.
Add `IpProtocol`, `AddressFamily` and `Namespace`.

The wrappers added with this patch are shared across the whole network
subsystem. For this reason, they are placed in the `net.rs` module file.

The enum `IpProtocol`, however, is placed in an individual `ip.rs`
submodule, allowing to place together all the ip-related structures,
such as wrappers for `iphdr`, `ip_auth_hdr`, etc.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
 rust/bindings/bindings_helper.h |   3 +
 rust/kernel/lib.rs              |   2 +
 rust/kernel/net.rs              | 180 ++++++++++++++++++++++++++++++++
 rust/kernel/net/ip.rs           |  73 +++++++++++++
 4 files changed, 258 insertions(+)
 create mode 100644 rust/kernel/net.rs
 create mode 100644 rust/kernel/net/ip.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 058954961bfc..7cc1bd73c77a 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -7,6 +7,9 @@
  */
 
 #include <linux/errname.h>
+#include <linux/netfilter.h>
+#include <linux/inet.h>
+#include <linux/tcp.h>
 #include <linux/slab.h>
 #include <linux/refcount.h>
 #include <linux/wait.h>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 85b261209977..8e6926d965e1 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -34,6 +34,8 @@
 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..1eda336b48e4
--- /dev/null
+++ b/rust/kernel/net.rs
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Network subsystem.
+//!
+//! This module contains the kernel APIs related to networking that have been ported or wrapped for
+//! usage by Rust code in the kernel.
+//!
+//! C header: [`include/linux/net.h`](../../../../include/linux/net.h) and related
+
+use crate::error::{code, Error};
+use core::cell::UnsafeCell;
+pub mod ip;
+
+/// The address family.
+///
+/// See [`man 7 address families`](https://man7.org/linux/man-pages/man7/address_families.7.html) for more information.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum AddressFamily {
+    /// Unspecified address family.
+    Unspec = bindings::AF_UNSPEC as isize,
+    /// Local to host (pipes and file-domain).
+    Unix = bindings::AF_UNIX as isize,
+    /// Internetwork: UDP, TCP, etc.
+    Inet = bindings::AF_INET as isize,
+    /// Amateur radio AX.25.
+    Ax25 = bindings::AF_AX25 as isize,
+    /// IPX.
+    Ipx = bindings::AF_IPX as isize,
+    /// Appletalk DDP.
+    Appletalk = bindings::AF_APPLETALK as isize,
+    /// AX.25 packet layer protocol.
+    Netrom = bindings::AF_NETROM as isize,
+    /// Bridge link.
+    Bridge = bindings::AF_BRIDGE as isize,
+    /// ATM PVCs.
+    Atmpvc = bindings::AF_ATMPVC as isize,
+    /// X.25 (ISO-8208).
+    X25 = bindings::AF_X25 as isize,
+    /// IPv6.
+    Inet6 = bindings::AF_INET6 as isize,
+    /// ROSE protocol.
+    Rose = bindings::AF_ROSE as isize,
+    /// DECnet protocol.
+    Decnet = bindings::AF_DECnet as isize,
+    /// 802.2LLC project.
+    Netbeui = bindings::AF_NETBEUI as isize,
+    /// Firewall hooks.
+    Security = bindings::AF_SECURITY as isize,
+    /// Key management protocol.
+    Key = bindings::AF_KEY as isize,
+    /// Netlink.
+    Netlink = bindings::AF_NETLINK as isize,
+    /// Low-level packet interface.
+    Packet = bindings::AF_PACKET as isize,
+    /// Acorn Econet protocol.
+    Econet = bindings::AF_ECONET as isize,
+    /// ATM SVCs.
+    Atmsvc = bindings::AF_ATMSVC as isize,
+    /// RDS sockets.
+    Rds = bindings::AF_RDS as isize,
+    /// IRDA sockets.
+    Irda = bindings::AF_IRDA as isize,
+    /// Generic PPP.
+    Pppox = bindings::AF_PPPOX as isize,
+    /// Legacy WAN networks protocol.
+    Wanpipe = bindings::AF_WANPIPE as isize,
+    /// LLC protocol.
+    Llc = bindings::AF_LLC as isize,
+    /// Infiniband.
+    Ib = bindings::AF_IB as isize,
+    /// Multiprotocol label switching.
+    Mpls = bindings::AF_MPLS as isize,
+    /// Controller Area Network.
+    Can = bindings::AF_CAN as isize,
+    /// TIPC sockets.
+    Tipc = bindings::AF_TIPC as isize,
+    /// Bluetooth sockets.
+    Bluetooth = bindings::AF_BLUETOOTH as isize,
+    /// IUCV sockets.
+    Iucv = bindings::AF_IUCV as isize,
+    /// RxRPC sockets.
+    Rxrpc = bindings::AF_RXRPC as isize,
+    /// Modular ISDN protocol.
+    Isdn = bindings::AF_ISDN as isize,
+    /// Nokia cellular modem interface.
+    Phonet = bindings::AF_PHONET as isize,
+    /// IEEE 802.15.4 sockets.
+    Ieee802154 = bindings::AF_IEEE802154 as isize,
+    /// CAIF sockets.
+    Caif = bindings::AF_CAIF as isize,
+    /// Kernel crypto API
+    Alg = bindings::AF_ALG as isize,
+    /// VMware VSockets.
+    Vsock = bindings::AF_VSOCK as isize,
+    /// KCM sockets.
+    Kcm = bindings::AF_KCM as isize,
+    /// Qualcomm IPC router protocol.
+    Qipcrtr = bindings::AF_QIPCRTR as isize,
+    /// SMC sockets.
+    Smc = bindings::AF_SMC as isize,
+    /// Express Data Path sockets.
+    Xdp = bindings::AF_XDP as isize,
+}
+
+impl From<AddressFamily> for isize {
+    fn from(family: AddressFamily) -> Self {
+        family as isize
+    }
+}
+
+impl TryFrom<isize> for AddressFamily {
+    type Error = Error;
+
+    fn try_from(value: isize) -> Result<Self, Self::Error> {
+        let val = value as u32;
+        match val {
+            bindings::AF_UNSPEC => Ok(Self::Unspec),
+            bindings::AF_UNIX => Ok(Self::Unix),
+            bindings::AF_INET => Ok(Self::Inet),
+            bindings::AF_AX25 => Ok(Self::Ax25),
+            bindings::AF_IPX => Ok(Self::Ipx),
+            bindings::AF_APPLETALK => Ok(Self::Appletalk),
+            bindings::AF_NETROM => Ok(Self::Netrom),
+            bindings::AF_BRIDGE => Ok(Self::Bridge),
+            bindings::AF_ATMPVC => Ok(Self::Atmpvc),
+            bindings::AF_X25 => Ok(Self::X25),
+            bindings::AF_INET6 => Ok(Self::Inet6),
+            bindings::AF_ROSE => Ok(Self::Rose),
+            bindings::AF_DECnet => Ok(Self::Decnet),
+            bindings::AF_NETBEUI => Ok(Self::Netbeui),
+            bindings::AF_SECURITY => Ok(Self::Security),
+            bindings::AF_KEY => Ok(Self::Key),
+            bindings::AF_NETLINK => Ok(Self::Netlink),
+            bindings::AF_PACKET => Ok(Self::Packet),
+            bindings::AF_ECONET => Ok(Self::Econet),
+            bindings::AF_ATMSVC => Ok(Self::Atmsvc),
+            bindings::AF_RDS => Ok(Self::Rds),
+            bindings::AF_IRDA => Ok(Self::Irda),
+            bindings::AF_PPPOX => Ok(Self::Pppox),
+            bindings::AF_WANPIPE => Ok(Self::Wanpipe),
+            bindings::AF_LLC => Ok(Self::Llc),
+            bindings::AF_IB => Ok(Self::Ib),
+            bindings::AF_MPLS => Ok(Self::Mpls),
+            bindings::AF_CAN => Ok(Self::Can),
+            bindings::AF_TIPC => Ok(Self::Tipc),
+            bindings::AF_BLUETOOTH => Ok(Self::Bluetooth),
+            bindings::AF_IUCV => Ok(Self::Iucv),
+            bindings::AF_RXRPC => Ok(Self::Rxrpc),
+            bindings::AF_ISDN => Ok(Self::Isdn),
+            bindings::AF_PHONET => Ok(Self::Phonet),
+            bindings::AF_IEEE802154 => Ok(Self::Ieee802154),
+            bindings::AF_CAIF => Ok(Self::Caif),
+            bindings::AF_ALG => Ok(Self::Alg),
+            bindings::AF_VSOCK => Ok(Self::Vsock),
+            bindings::AF_KCM => Ok(Self::Kcm),
+            bindings::AF_QIPCRTR => Ok(Self::Qipcrtr),
+            bindings::AF_SMC => Ok(Self::Smc),
+            bindings::AF_XDP => Ok(Self::Xdp),
+            _ => Err(code::EINVAL),
+        }
+    }
+}
+
+/// Network namespace.
+///
+/// Wraps the `net` struct.
+#[repr(transparent)]
+pub struct Namespace(UnsafeCell<bindings::net>);
+
+/// The global network namespace.
+///
+/// This is the default and initial namespace.
+/// This function replaces the C `init_net` global variable.
+pub fn init_net() -> &'static Namespace {
+    // SAFETY: `init_net` is a global variable and is always valid.
+    let ptr = unsafe { core::ptr::addr_of!(bindings::init_net) };
+    // SAFETY: the address of `init_net` is always valid, always points to initialized memory,
+    // and is always aligned.
+    unsafe { &*(ptr.cast()) }
+}
diff --git a/rust/kernel/net/ip.rs b/rust/kernel/net/ip.rs
new file mode 100644
index 000000000000..84f98d356137
--- /dev/null
+++ b/rust/kernel/net/ip.rs
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! IP protocol definitions.
+//!
+//! This module contains the kernel structures and functions related to IP protocols.
+//!
+//! C headers:
+//! - [`include/linux/in.h`](../../../../include/linux/in.h)
+//! - [`include/linux/ip.h`](../../../../include/linux/ip.h)
+//! - [`include/uapi/linux/ip.h`](../../../../include/uapi/linux/ip.h)
+
+/// The Ip protocol.
+///
+/// See [`tools/include/uapi/linux/in.h`](../../../../tools/include/uapi/linux/in.h)
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum IpProtocol {
+    /// Dummy protocol for TCP
+    Ip = bindings::IPPROTO_IP as isize,
+    /// Internet Control Message Protocol
+    Icmp = bindings::IPPROTO_ICMP as isize,
+    /// Internet Group Management Protocol
+    Igmp = bindings::IPPROTO_IGMP as isize,
+    /// IPIP tunnels (older KA9Q tunnels use 94)
+    IpIp = bindings::IPPROTO_IPIP as isize,
+    /// Transmission Control Protocol
+    Tcp = bindings::IPPROTO_TCP as isize,
+    /// Exterior Gateway Protocol
+    Egp = bindings::IPPROTO_EGP as isize,
+    /// PUP protocol
+    Pup = bindings::IPPROTO_PUP as isize,
+    /// User Datagram Protocol
+    Udp = bindings::IPPROTO_UDP as isize,
+    /// XNS Idp protocol
+    Idp = bindings::IPPROTO_IDP as isize,
+    /// SO Transport Protocol Class 4
+    Tp = bindings::IPPROTO_TP as isize,
+    /// Datagram Congestion Control Protocol
+    Dccp = bindings::IPPROTO_DCCP as isize,
+    /// Ipv6-in-Ipv4 tunnelling
+    Ipv6 = bindings::IPPROTO_IPV6 as isize,
+    /// Rsvp Protocol
+    Rsvp = bindings::IPPROTO_RSVP as isize,
+    /// Cisco GRE tunnels (rfc 1701,1702)
+    Gre = bindings::IPPROTO_GRE as isize,
+    /// Encapsulation Security Payload protocol
+    Esp = bindings::IPPROTO_ESP as isize,
+    /// Authentication Header protocol
+    Ah = bindings::IPPROTO_AH as isize,
+    /// Multicast Transport Protocol
+    Mtp = bindings::IPPROTO_MTP as isize,
+    /// Ip option pseudo header for BEET
+    Beetph = bindings::IPPROTO_BEETPH as isize,
+    /// Encapsulation Header
+    Encap = bindings::IPPROTO_ENCAP as isize,
+    /// Protocol Independent Multicast
+    Pim = bindings::IPPROTO_PIM as isize,
+    /// Compression Header Protocol
+    Comp = bindings::IPPROTO_COMP as isize,
+    /// Layer 2 Tunnelling Protocol
+    L2Tp = bindings::IPPROTO_L2TP as isize,
+    /// Stream Control Transport Protocol
+    Sctp = bindings::IPPROTO_SCTP as isize,
+    /// Udp-Lite (Rfc 3828)
+    UdpLite = bindings::IPPROTO_UDPLITE as isize,
+    /// Mpls in Ip (Rfc 4023)
+    Mpls = bindings::IPPROTO_MPLS as isize,
+    /// Ethernet-within-Ipv6 Encapsulation
+    Ethernet = bindings::IPPROTO_ETHERNET as isize,
+    /// Raw Ip packets
+    Raw = bindings::IPPROTO_RAW as isize,
+    /// Multipath Tcp connection
+    Mptcp = bindings::IPPROTO_MPTCP as isize,
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH 2/7] rust: net: add ip and socket address bindings.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 1/7] rust: net: add net module files and shared enums Michele Dalle Rive
@ 2023-08-14  9:22 ` Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 3/7] rust: net: add socket-related flags and flagset Michele Dalle Rive
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:22 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Create structures to handle addresses: `Ipv4Addr`, `Ipv6Addr`,
`SocketAddr`, `SocketAddrV4` and `SocketAddrV6`.

These structures are meant to be as similar as possible to the ones in
Rust `std::net`, while, at the same time, providing functionalities
available in the kernel.

Some extra structures are added, compared to `std`:
- `SocketAddrStorage`: wraps `struct sockaddr_storage` and is used to
  interact with the kernel functions when the type of socket address is
  unknown. Since it is only used for FFI, it is crate-public.
- `GenericSocketAddr`: trait that defines shared functions and traits
  amont all socket addresses.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
A few questions here:
- Should `SocketAddrStorage` be crate-public or public? My reasoning is
  that modules should be using `SocketAddr` for an "unspecified" socket
  address type; however, having `SocketAddrStorage` available could give
  the freedom of eventually using bindings directly to do more complex
  tasks.
- Is `GenericSocketAddr` useful? I thought it could be convenient
  to have a socket address trait, as a sort of "superclass" for all
  socket addresses. However, I think it has no particular use, since
  there is `SocketAddr`.
- Should the addresses be divided in two files, one for ip addresses and
  one for socket addresses? Or everything together works?

 rust/kernel/net.rs      |    2 +
 rust/kernel/net/addr.rs | 1215 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 1217 insertions(+)
 create mode 100644 rust/kernel/net/addr.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index 1eda336b48e4..346e7374e614 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -9,6 +9,8 @@
 
 use crate::error::{code, Error};
 use core::cell::UnsafeCell;
+
+pub mod addr;
 pub mod ip;
 
 /// The address family.
diff --git a/rust/kernel/net/addr.rs b/rust/kernel/net/addr.rs
new file mode 100644
index 000000000000..e6b1ba7320db
--- /dev/null
+++ b/rust/kernel/net/addr.rs
@@ -0,0 +1,1215 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Network address types.
+//!
+//! This module contains the types and APIs related to network addresses.
+//! The methods and types of this API are inspired by the [Rust standard library's `std::net` module](https://doc.rust-lang.org/std/net/index.html),
+//! but have been ported to use the kernel's C APIs.
+
+use crate::error::{code, Error, Result};
+use crate::net::{init_net, AddressFamily, Namespace};
+use crate::str::{CStr, CString};
+use crate::{c_str, fmt};
+use core::cmp::Ordering;
+use core::fmt::{Debug, Display, Formatter};
+use core::hash::{Hash, Hasher};
+use core::mem::MaybeUninit;
+use core::ptr;
+use core::str::FromStr;
+
+/// An IPv4 address.
+///
+/// Wraps a `struct in_addr`.
+#[derive(Default, Copy, Clone)]
+#[repr(transparent)]
+pub struct Ipv4Addr(pub(crate) bindings::in_addr);
+
+impl Ipv4Addr {
+    /// The maximum length of an IPv4 address string.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 15;
+
+    /// Create a new IPv4 address from four 8-bit integers.
+    ///
+    /// The IP address will be `a.b.c.d`.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// ```
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
+        Self::from_bits(u32::from_be_bytes([a, b, c, d]))
+    }
+
+    /// Get the octets of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// let expected = [192, 168, 0, 1];
+    /// assert_eq!(addr.octets(), &expected);
+    /// ```
+    pub const fn octets(&self) -> &[u8; 4] {
+        // SAFETY: The s_addr field is a 32-bit integer, which is the same size as the array.
+        unsafe { &*(&self.0.s_addr as *const _ as *const [u8; 4]) }
+    }
+
+    /// Create a new IPv4 address from a 32-bit integer.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from_bits(0xc0a80001);
+    /// assert_eq!(addr, Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
+    pub const fn from_bits(bits: u32) -> Self {
+        Ipv4Addr(bindings::in_addr {
+            s_addr: bits.to_be(),
+        })
+    }
+
+    /// Get the 32-bit integer representation of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// assert_eq!(addr.to_bits(), 0xc0a80001);
+    /// ```
+    pub const fn to_bits(&self) -> u32 {
+        u32::from_be(self.0.s_addr)
+    }
+
+    /// The broadcast address: `255.255.255.255`
+    ///
+    /// Used to send a message to all hosts on the network.
+    pub const BROADCAST: Self = Self::new(255, 255, 255, 255);
+
+    /// "None" address
+    ///
+    /// Can be used as return value to indicate an error.
+    pub const NONE: Self = Self::new(255, 255, 255, 255);
+
+    /// The "any" address: `0.0.0.0`
+    /// Used to accept any incoming message.
+    pub const UNSPECIFIED: Self = Self::new(0, 0, 0, 0);
+
+    /// A dummy address: `192.0.0.8`
+    /// Used as ICMP reply source if no address is set.
+    pub const DUMMY: Self = Self::new(192, 0, 0, 8);
+
+    /// The loopback address: `127.0.0.1`
+    /// Used to send a message to the local host.
+    pub const LOOPBACK: Self = Self::new(127, 0, 0, 1);
+}
+
+impl From<[u8; 4]> for Ipv4Addr {
+    /// Create a new IPv4 address from an array of 8-bit integers.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from([192, 168, 0, 1]);
+    /// assert_eq!(addr, Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
+    fn from(octets: [u8; 4]) -> Self {
+        Self::new(octets[0], octets[1], octets[2], octets[3])
+    }
+}
+
+impl From<Ipv4Addr> for u32 {
+    /// Get the 32-bit integer representation of the address.
+    ///
+    /// This is the same as calling [`Ipv4Addr::to_bits`].
+    fn from(addr: Ipv4Addr) -> Self {
+        addr.to_bits()
+    }
+}
+
+impl From<u32> for Ipv4Addr {
+    /// Create a new IPv4 address from a 32-bit integer.
+    ///
+    /// This is the same as calling [`Ipv4Addr::from_bits`].
+    fn from(bits: u32) -> Self {
+        Self::from_bits(bits)
+    }
+}
+
+impl PartialEq<Ipv4Addr> for Ipv4Addr {
+    /// Compare two IPv4 addresses.
+    ///
+    /// Returns `true` if the addresses are made up of the same bytes.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr1 = Ipv4Addr::new(192, 168, 0, 1);
+    /// let addr2 = Ipv4Addr::new(192, 168, 0, 1);
+    /// assert_eq!(addr1, addr2);
+    ///
+    /// let addr3 = Ipv4Addr::new(192, 168, 0, 2);
+    /// assert_ne!(addr1, addr3);
+    /// ```
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        self.to_bits() == other.to_bits()
+    }
+}
+
+impl Eq for Ipv4Addr {}
+
+impl Hash for Ipv4Addr {
+    /// Hash an IPv4 address.
+    ///
+    /// The trait cannot be derived because the `in_addr` struct does not implement `Hash`.
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.to_bits().hash(state)
+    }
+}
+
+impl PartialOrd for Ipv4Addr {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.to_bits().partial_cmp(&other.to_bits())
+    }
+}
+
+impl Ord for Ipv4Addr {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.to_bits().cmp(&other.to_bits())
+    }
+}
+
+/// An IPv6 address.
+///
+/// Wraps a `struct in6_addr`.
+#[derive(Default, Copy, Clone)]
+#[repr(transparent)]
+pub struct Ipv6Addr(pub(crate) bindings::in6_addr);
+
+impl Ipv6Addr {
+    /// The maximum length of an IPv6 address string.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 45;
+
+    /// Create a new IPv6 address from eight 16-bit integers.
+    ///
+    /// The 16-bit integers are transformed in network order.
+    ///
+    /// The IP address will be `a:b:c:d:e:f:g:h`.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// ```
+    #[allow(clippy::too_many_arguments)]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr16: [
+                    a.to_be(),
+                    b.to_be(),
+                    c.to_be(),
+                    d.to_be(),
+                    e.to_be(),
+                    f.to_be(),
+                    g.to_be(),
+                    h.to_be(),
+                ],
+            },
+        })
+    }
+
+    /// Get the octets of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// let expected = [0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34];
+    /// assert_eq!(addr.octets(), &expected);
+    /// ```
+    pub const fn octets(&self) -> &[u8; 16] {
+        // SAFETY: The u6_addr8 field is a [u8; 16] array.
+        unsafe { &self.0.in6_u.u6_addr8 }
+    }
+
+    /// Get the segments of the address.
+    ///
+    /// A segment is a 16-bit integer.
+    /// The segments are in network order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// let expected = [0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334];
+    /// assert_eq!(addr.segments(), &expected);
+    /// ```
+    pub const fn segments(&self) -> &[u16; 8] {
+        // SAFETY: The u6_addr16 field is a [u16; 8] array.
+        unsafe { &self.0.in6_u.u6_addr16 }
+    }
+
+    /// Create a 128-bit integer representation of the address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// assert_eq!(addr.to_bits(), 0x20010db885a3000000008a2e03707334);
+    /// ```
+    pub fn to_bits(&self) -> u128 {
+        u128::from_be_bytes(*self.octets() as _)
+    }
+
+    /// Create a new IPv6 address from a 128-bit integer.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from_bits(0x20010db885a3000000008a2e03707334);
+    /// assert_eq!(addr, Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334));
+    /// ```
+    pub const fn from_bits(bits: u128) -> Self {
+        Ipv6Addr(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 {
+                u6_addr8: bits.to_be_bytes() as _,
+            },
+        })
+    }
+
+    /// The "any" address: `::`
+    ///
+    /// Used to accept any incoming message.
+    /// Should not be used as a destination address.
+    pub const ANY: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// The loopback address: `::1`
+    ///
+    /// Used to send a message to the local host.
+    pub const LOOPBACK: Self = Self::new(0, 0, 0, 0, 0, 0, 0, 1);
+}
+
+impl From<[u16; 8]> for Ipv6Addr {
+    fn from(value: [u16; 8]) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 { u6_addr16: value },
+        })
+    }
+}
+
+impl From<[u8; 16]> for Ipv6Addr {
+    fn from(value: [u8; 16]) -> Self {
+        Self(bindings::in6_addr {
+            in6_u: bindings::in6_addr__bindgen_ty_1 { u6_addr8: value },
+        })
+    }
+}
+
+impl From<Ipv6Addr> for u128 {
+    fn from(addr: Ipv6Addr) -> Self {
+        addr.to_bits()
+    }
+}
+
+impl From<u128> for Ipv6Addr {
+    fn from(bits: u128) -> Self {
+        Self::from_bits(bits)
+    }
+}
+
+impl PartialEq for Ipv6Addr {
+    fn eq(&self, other: &Self) -> bool {
+        self.to_bits() == other.to_bits()
+    }
+}
+
+impl Eq for Ipv6Addr {}
+
+impl Hash for Ipv6Addr {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.to_bits().hash(state)
+    }
+}
+
+impl PartialOrd for Ipv6Addr {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.to_bits().partial_cmp(&other.to_bits())
+    }
+}
+
+impl Ord for Ipv6Addr {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.to_bits().cmp(&other.to_bits())
+    }
+}
+
+/// A wrapper for a generic socket address.
+///
+/// Wraps a C `struct sockaddr_storage`.
+/// Unlike [`SocketAddr`], this struct is meant to be used internally only,
+/// as a parameter for kernel function calls.
+#[repr(transparent)]
+#[derive(Copy, Clone, Default)]
+pub(crate) struct SocketAddrStorage(pub(crate) bindings::__kernel_sockaddr_storage);
+
+impl SocketAddrStorage {
+    /// Returns the family of the address.
+    pub(crate) fn family(&self) -> Result<AddressFamily, Error> {
+        // SAFETY: The union access is safe because the `ss_family` field is always valid.
+        let val: isize = unsafe { self.0.__bindgen_anon_1.__bindgen_anon_1.ss_family as _ };
+        AddressFamily::try_from(val)
+    }
+
+    pub(crate) fn into<T: GenericSocketAddr>(self) -> T {
+        // SAFETY: The `self.0` field is a `struct sockaddr_storage` which is guaranteed to be large enough to hold any socket address.
+        unsafe { *(&self.0 as *const _ as *const T) }
+    }
+}
+
+/// A generic Socket Address. Acts like a `struct sockaddr_storage`.
+/// `sockaddr_storage` is used instead of `sockaddr` because it is guaranteed to be large enough to hold any socket address.
+///
+/// The purpose of this enum is to be used as a generic parameter for functions that can take any type of address.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum SocketAddr {
+    /// An IPv4 address.
+    V4(SocketAddrV4),
+    /// An IPv6 address.
+    V6(SocketAddrV6),
+}
+
+impl SocketAddr {
+    /// Returns the size in bytes of the concrete address contained.
+    ///
+    /// Used in the kernel functions that take a parameter with the size of the socket address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// assert_eq!(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80)).size(),
+    ///           core::mem::size_of::<SocketAddrV4>());
+    pub fn size(&self) -> usize {
+        match self {
+            SocketAddr::V4(_) => SocketAddrV4::size(),
+            SocketAddr::V6(_) => SocketAddrV6::size(),
+        }
+    }
+
+    /// Returns the address family of the concrete address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// use kernel::net::AddressFamily;
+    /// assert_eq!(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80)).family(),
+    ///          AddressFamily::Inet);
+    /// ```
+    pub fn family(&self) -> AddressFamily {
+        match self {
+            SocketAddr::V4(_) => AddressFamily::Inet,
+            SocketAddr::V6(_) => AddressFamily::Inet6,
+        }
+    }
+
+    /// Returns a pointer to the C `struct sockaddr_storage` contained.
+    /// Used in the kernel functions that take a pointer to a socket address.
+    pub(crate) fn as_ptr(&self) -> *const SocketAddrStorage {
+        match self {
+            SocketAddr::V4(addr) => addr as *const _ as _,
+            SocketAddr::V6(addr) => addr as *const _ as _,
+        }
+    }
+
+    /// Creates a `SocketAddr` from a C `struct sockaddr_storage`.
+    /// The function consumes the `struct sockaddr_storage`.
+    /// Used in the kernel functions that return a socket address.
+    ///
+    /// # Panics
+    /// Panics if the address family of the `struct sockaddr_storage` is invalid.
+    /// This should never happen.
+    /// If it does, it is likely because of an invalid pointer.
+    pub(crate) fn try_from_raw(sockaddr: SocketAddrStorage) -> Result<Self> {
+        match sockaddr.family()? {
+            AddressFamily::Inet => Ok(SocketAddr::V4(sockaddr.into())),
+            AddressFamily::Inet6 => Ok(SocketAddr::V6(sockaddr.into())),
+            _ => Err(code::EINVAL),
+        }
+    }
+}
+
+impl From<SocketAddrV4> for SocketAddr {
+    fn from(value: SocketAddrV4) -> Self {
+        SocketAddr::V4(value)
+    }
+}
+
+impl From<SocketAddrV6> for SocketAddr {
+    fn from(value: SocketAddrV6) -> Self {
+        SocketAddr::V6(value)
+    }
+}
+
+impl TryFrom<SocketAddr> for SocketAddrV4 {
+    type Error = Error;
+
+    fn try_from(value: SocketAddr) -> core::result::Result<Self, Self::Error> {
+        match value {
+            SocketAddr::V4(addr) => Ok(addr),
+            _ => Err(Error::from_errno(bindings::EAFNOSUPPORT as _)),
+        }
+    }
+}
+
+impl TryFrom<SocketAddr> for SocketAddrV6 {
+    type Error = Error;
+
+    fn try_from(value: SocketAddr) -> core::result::Result<Self, Self::Error> {
+        match value {
+            SocketAddr::V6(addr) => Ok(addr),
+            _ => Err(Error::from_errno(bindings::EAFNOSUPPORT as _)),
+        }
+    }
+}
+
+/// Generic trait for socket addresses.
+///
+/// The purpose of this trait is:
+/// - To force all socket addresses to have a size and an address family.
+/// - Force all socket addresses to implement specific built-in traits.
+pub trait GenericSocketAddr:
+    Sized + Copy + Clone + PartialEq + Eq + PartialOrd + Ord + Hash + Display
+{
+    /// Returns the size in bytes of the concrete address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::bindings;
+    /// use kernel::net::addr::{GenericSocketAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// assert_eq!(SocketAddrV4::size(), core::mem::size_of::<bindings::sockaddr_in>());
+    /// ```
+    fn size() -> usize
+    where
+        Self: Sized,
+    {
+        core::mem::size_of::<Self>()
+    }
+
+    /// Returns the address family of the concrete address.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use kernel::net::addr::{GenericSocketAddr, SocketAddrV4};
+    /// use kernel::net::AddressFamily;
+    /// assert_eq!(SocketAddrV4::family(), AddressFamily::Inet);
+    /// ```
+    fn family() -> AddressFamily;
+}
+
+/// IPv4 socket address.
+///
+/// Wraps a C `struct sockaddr_in`.
+///
+/// # Examples
+/// ```rust
+/// use kernel::bindings;
+/// use kernel::net::addr::{GenericSocketAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
+/// let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+/// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+/// assert_eq!(SocketAddrV4::size(), core::mem::size_of::<bindings::sockaddr_in>());
+/// ```
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+pub struct SocketAddrV4(pub(crate) bindings::sockaddr_in);
+
+impl SocketAddrV4 {
+    /// The maximum length of a IPv4 socket address string representation.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 21;
+
+    /// Creates a new IPv4 socket address from an IP address and a port.
+    ///
+    /// The port does not need to be in network byte order.
+    pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
+        Self(bindings::sockaddr_in {
+            sin_family: AddressFamily::Inet as _,
+            sin_port: port.to_be(),
+            sin_addr: addr.0,
+            __pad: [0; 8],
+        })
+    }
+
+    /// Returns a reference to the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let ip = Ipv4Addr::new(192, 168, 0, 1);
+    /// let addr = SocketAddrV4::new(ip, 80);
+    /// assert_eq!(addr.ip(), &ip);
+    /// ```
+    pub const fn ip(&self) -> &Ipv4Addr {
+        // SAFETY: The [Ipv4Addr] is a transparent representation of the C `struct in_addr`,
+        // which is the type of `sin_addr`. Therefore, the conversion is safe.
+        unsafe { &*(&self.0.sin_addr as *const _ as *const Ipv4Addr) }
+    }
+
+    /// Change the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let mut addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+    /// addr.set_ip(Ipv4Addr::new(192, 168, 0, 2));
+    /// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 0, 2));
+    /// ```
+    pub fn set_ip(&mut self, ip: Ipv4Addr) {
+        self.0.sin_addr = ip.0;
+    }
+
+    /// Returns the port contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+    /// assert_eq!(addr.port(), 81);
+    /// ```
+    pub const fn port(&self) -> u16 {
+        self.0.sin_port.to_be()
+    }
+
+    /// Change the port contained.
+    ///
+    /// The port does not need to be in network byte order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// let mut addr = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 80);
+    /// addr.set_port(81);
+    /// assert_eq!(addr.port(), 81);
+    /// ```
+    pub fn set_port(&mut self, port: u16) {
+        self.0.sin_port = port.to_be();
+    }
+}
+
+impl GenericSocketAddr for SocketAddrV4 {
+    /// Returns the family of the address.
+    ///
+    /// # Invariants
+    /// The family is always [AddressFamily::Inet].
+    fn family() -> AddressFamily {
+        AddressFamily::Inet
+    }
+}
+
+impl PartialEq<SocketAddrV4> for SocketAddrV4 {
+    fn eq(&self, other: &SocketAddrV4) -> bool {
+        self.ip() == other.ip() && self.port() == other.port()
+    }
+}
+
+impl Eq for SocketAddrV4 {}
+
+impl Hash for SocketAddrV4 {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        (self.ip(), self.port()).hash(state)
+    }
+}
+
+impl PartialOrd for SocketAddrV4 {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for SocketAddrV4 {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (self.ip(), self.port()).cmp(&(other.ip(), other.port()))
+    }
+}
+
+/// IPv6 socket address.
+///
+/// Wraps a C `struct sockaddr_in6`.
+///
+/// # Examples
+/// ```rust
+/// use kernel::bindings;
+/// use kernel::net::addr::{GenericSocketAddr, Ipv6Addr, SocketAddr, SocketAddrV6};
+///
+/// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 0);
+/// assert_eq!(addr.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+/// assert_eq!(SocketAddrV6::size(), core::mem::size_of::<bindings::sockaddr_in6>());
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+pub struct SocketAddrV6(pub(crate) bindings::sockaddr_in6);
+
+impl SocketAddrV6 {
+    /// The maximum length of a IPv6 socket address string representation.
+    ///
+    /// This is the length of the string representation of the address.
+    /// It does not include the null terminator.
+    pub const MAX_STRING_LEN: usize = 74;
+
+    /// Creates a new IPv6 socket address from an IP address, a port, a flowinfo and a scope_id.
+    /// The port does not need to be in network byte order.
+    pub const fn new(addr: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> Self {
+        Self(bindings::sockaddr_in6 {
+            sin6_family: AddressFamily::Inet6 as _,
+            sin6_port: port.to_be(),
+            sin6_flowinfo: flowinfo,
+            sin6_addr: addr.0,
+            sin6_scope_id: scope_id,
+        })
+    }
+
+    /// Returns a reference to the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let ip = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    /// let addr = SocketAddrV6::new(ip, 80, 0, 0);
+    /// assert_eq!(addr.ip(), &ip);
+    /// ```
+    pub const fn ip(&self) -> &Ipv6Addr {
+        // SAFETY: The [Ipv6Addr] is a transparent representation of the C `struct in6_addr`,
+        // which is the type of `sin6_addr`. Therefore, the conversion is safe.
+        unsafe { &*(&self.0.sin6_addr as *const _ as *const Ipv6Addr) }
+    }
+
+    /// Change the IP address contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let ip1 = Ipv6Addr::LOOPBACK;
+    /// let ip2 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2);
+    /// let mut addr = SocketAddrV6::new(ip1, 80, 0, 0);
+    /// addr.set_ip(ip2);
+    /// assert_eq!(addr.ip(), &ip2);
+    /// ```
+    pub fn set_ip(&mut self, addr: Ipv6Addr) {
+        self.0.sin6_addr = addr.0;
+    }
+
+    /// Returns the port contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 0);
+    /// assert_eq!(addr.port(), 80);
+    /// ```
+    pub const fn port(&self) -> u16 {
+        self.0.sin6_port.to_be()
+    }
+
+    /// Change the port contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let mut addr = SocketAddrV6::new(Ipv6Addr::LOOPBACK, 80, 0, 0);
+    /// addr.set_port(443);
+    /// assert_eq!(addr.port(), 443);
+    /// ```
+    pub fn set_port(&mut self, port: u16) {
+        self.0.sin6_port = port.to_be();
+    }
+
+    /// Returns the flowinfo contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 0);
+    /// assert_eq!(addr.flowinfo(), 0);
+    /// ```
+    pub const fn flowinfo(&self) -> u32 {
+        self.0.sin6_flowinfo as _
+    }
+
+    /// Change the flowinfo contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let mut addr = SocketAddrV6::new(Ipv6Addr::LOOPBACK, 80, 0, 0);
+    /// addr.set_flowinfo(1);
+    /// assert_eq!(addr.flowinfo(), 1);
+    /// ```
+    pub fn set_flowinfo(&mut self, flowinfo: u32) {
+        self.0.sin6_flowinfo = flowinfo;
+    }
+
+    /// Returns the scope_id contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80, 0, 1);
+    /// assert_eq!(addr.scope_id(), 1);
+    /// ```
+    pub const fn scope_id(&self) -> u32 {
+        self.0.sin6_scope_id as _
+    }
+
+    /// Change the scope_id contained.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let mut addr = SocketAddrV6::new(Ipv6Addr::LOOPBACK, 80, 0, 0);
+    /// addr.set_scope_id(1);
+    /// assert_eq!(addr.scope_id(), 1);
+    /// ```
+    pub fn set_scope_id(&mut self, scope_id: u32) {
+        self.0.sin6_scope_id = scope_id;
+    }
+}
+
+impl GenericSocketAddr for SocketAddrV6 {
+    /// Returns the family of the address.
+    ///
+    /// # Invariants
+    /// The family is always [AddressFamily::Inet6].
+    fn family() -> AddressFamily {
+        AddressFamily::Inet6
+    }
+}
+
+impl PartialEq<SocketAddrV6> for SocketAddrV6 {
+    fn eq(&self, other: &SocketAddrV6) -> bool {
+        self.ip() == other.ip()
+            && self.port() == other.port()
+            && self.flowinfo() == other.flowinfo()
+            && self.scope_id() == other.scope_id()
+    }
+}
+
+impl Eq for SocketAddrV6 {}
+
+impl Hash for SocketAddrV6 {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        (self.ip(), self.port(), self.flowinfo(), self.scope_id()).hash(state)
+    }
+}
+
+impl PartialOrd for SocketAddrV6 {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for SocketAddrV6 {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (self.ip(), self.port(), self.flowinfo(), self.scope_id()).cmp(&(
+            other.ip(),
+            other.port(),
+            other.flowinfo(),
+            other.scope_id(),
+        ))
+    }
+}
+
+/// Create a Socket address from a string.
+///
+/// This method is a wrapper for the `inet_pton_with_scope` C function, which transforms a string
+/// to the specified sockaddr* structure.
+fn address_from_string<T: GenericSocketAddr>(src: &str, port: &str, net: &Namespace) -> Result<T> {
+    let src = CString::try_from_fmt(fmt!("{}", src))?;
+    let port = CString::try_from_fmt(fmt!("{}", port))?;
+    let mut addr = MaybeUninit::<T>::zeroed();
+
+    // SAFETY: FFI call, all pointers are valid for the duration of the call.
+    //         The address family matches the address structure.
+    match unsafe {
+        bindings::inet_pton_with_scope(
+            net as *const _ as *mut bindings::net as _,
+            T::family() as _,
+            src.as_ptr() as _,
+            port.as_ptr() as _,
+            addr.as_mut_ptr() as _,
+        )
+    } {
+        // SAFETY: The address was initialized by the C function.
+        //         Whatever was not initialized, e.g. flow info or scope id for ipv6, are zeroed.
+        0 => Ok(unsafe { addr.assume_init() }),
+        errno => Err(Error::from_errno(errno as _)),
+    }
+}
+
+/// Write the string representation of the `T` address to the formatter.
+///
+/// This function is used to implement the `Display` trait for each address.
+///
+/// The `cfmt` parameter is the C string format used to format the address.
+/// For example, the format for an IPv4 address is `"%pI4"`.
+///
+/// The `BUF_LEN` parameter is the size of the buffer used to format the address, including the null terminator.
+///
+/// # Safety
+/// In order to have a correct output, the `cfmt` parameter must be a valid C string format for the `T` address.
+/// Also, the `BUF_LEN` parameter must be at least the length of the string representation of the address.
+unsafe fn write_addr<const BUF_LEN: usize, T: Sized>(
+    formatter: &mut Formatter<'_>,
+    cfmt: &CStr,
+    addr: &T,
+) -> core::fmt::Result {
+    let mut buff = [0u8; BUF_LEN];
+    // SAFETY: the buffer is big enough to contain the string representation of the address.
+    //         The format is valid for the address.
+    let s = match unsafe {
+        bindings::snprintf(
+            buff.as_mut_ptr() as _,
+            BUF_LEN as _,
+            cfmt.as_ptr() as _,
+            addr as *const T,
+        )
+    } {
+        n if n < 0 => Err(()),
+
+        // the buffer is probably bigger than the actual string: truncate at the first null byte
+        _ => buff
+            .iter()
+            .position(|&c| c == 0)
+            // SAFETY: the buffer contains a UTF-8 valid string and contains a single null terminator.
+            .map(|i| unsafe { core::str::from_utf8_unchecked(&buff[..i]) })
+            .ok_or(()),
+    };
+    match s {
+        Ok(s) => write!(formatter, "{}", s),
+        Err(_) => Err(core::fmt::Error),
+    }
+}
+
+impl Display for Ipv4Addr {
+    /// Display the address as a string.
+    /// The bytes are in network order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv4Addr;
+    /// use kernel::pr_info;
+    ///
+    /// let addr = Ipv4Addr::new(192, 168, 0, 1);
+    /// pr_info!("{}", addr); // prints "192.168.0.1"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is the length of 255.255.255.255, the biggest Ipv4Addr string.
+        //         +1 for the null terminator.
+        unsafe {
+            write_addr::<{ Ipv4Addr::MAX_STRING_LEN + 1 }, Ipv4Addr>(f, c_str!("%pI4"), self)
+                .map_err(|_| core::fmt::Error)
+        }
+    }
+}
+
+impl Debug for Ipv4Addr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "Ipv4Addr({})", self)
+    }
+}
+
+impl FromStr for Ipv4Addr {
+    type Err = ();
+
+    /// Create a new IPv4 address from a string.
+    /// The string must be in the format `a.b.c.d`, where `a`, `b`, `c` and `d` are 8-bit integers.
+    ///
+    /// # Examples
+    /// Valid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from_str("192.168.0.1");
+    /// assert_eq!(addr, Ok(Ipv4Addr::new(192, 168, 0, 1)));
+    /// ```
+    ///
+    /// Invalid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv4Addr;
+    ///
+    /// let mut addr = Ipv4Addr::from_str("invalid");
+    /// assert_eq!(addr, Err(()));
+    ///
+    /// addr = Ipv4Addr::from_str("280.168.0.1");
+    /// assert_eq!(addr, Err(()));
+    ///
+    /// addr = Ipv4Addr::from_str("0.0.0.0.0");
+    /// assert_eq!(addr, Err(()));
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let mut buffer = [0u8; 4];
+        // SAFETY: FFI call,
+        //         there is no need to construct a NULL-terminated string, as the length is passed.
+        match unsafe {
+            bindings::in4_pton(
+                s.as_ptr() as *const _,
+                s.len() as _,
+                buffer.as_mut_ptr() as _,
+                -1,
+                ptr::null_mut(),
+            )
+        } {
+            1 => Ok(Ipv4Addr::from(buffer)),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Display for Ipv6Addr {
+    /// Display the address as a string.
+    /// The bytes are in network order.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::Ipv6Addr;
+    /// use kernel::pr_info;
+    ///
+    /// let addr = Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334);
+    /// pr_info!("{}", addr); // prints "2001:db8:85a3::8a2e:370:7334"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is the length of ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the biggest Ipv6Addr string.
+        unsafe {
+            write_addr::<{ Ipv6Addr::MAX_STRING_LEN + 1 }, Ipv6Addr>(f, c_str!("%pI6c"), self)
+        }
+    }
+}
+
+impl Debug for Ipv6Addr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "Ipv6Addr({})", self)
+    }
+}
+
+impl FromStr for Ipv6Addr {
+    type Err = ();
+
+    /// Create a new IPv6 address from a string.
+    ///
+    /// The address must follow the format described in [RFC 4291](https://tools.ietf.org/html/rfc4291#section-2.2).
+    ///
+    /// # Examples
+    /// Valid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from_str("2001:db8:85a3:0:0:8a2e:370:7334").unwrap();
+    /// assert_eq!(addr, Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334));
+    /// ```
+    ///
+    /// Invalid addresses:
+    /// ```rust
+    /// use core::str::FromStr;
+    /// use kernel::net::addr::Ipv6Addr;
+    ///
+    /// let mut addr = Ipv6Addr::from_str("invalid");
+    /// assert_eq!(addr, Err(()));
+    ///
+    /// addr = Ipv6Addr::from_str("2001:db8:85a3:0:0:8a2e:370:7334:1234");
+    /// assert_eq!(addr, Err(()));
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let mut buffer = [0u8; 16];
+        // SAFETY: FFI call,
+        //         there is no need to construct a NULL-terminated string, as the length is passed.
+        match unsafe {
+            bindings::in6_pton(
+                s.as_ptr() as _,
+                s.len() as _,
+                buffer.as_mut_ptr() as _,
+                -1,
+                ptr::null_mut(),
+            )
+        } {
+            1 => Ok(Ipv6Addr::from(buffer)),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Display for SocketAddr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        match self {
+            SocketAddr::V4(addr) => Display::fmt(addr, f),
+            SocketAddr::V6(addr) => Display::fmt(addr, f),
+        }
+    }
+}
+
+impl Debug for SocketAddr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "SocketAddr({})", self)
+    }
+}
+
+impl FromStr for SocketAddr {
+    type Err = Error;
+
+    fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
+        let funcs = [
+            |s| SocketAddrV4::from_str(s).map(SocketAddr::V4),
+            |s| SocketAddrV6::from_str(s).map(SocketAddr::V6),
+        ];
+
+        funcs.iter().find_map(|f| f(s).ok()).ok_or(code::EINVAL)
+    }
+}
+
+impl Display for SocketAddrV4 {
+    /// Display the address as a string.
+    ///
+    /// The output is of the form `address:port`, where `address` is the IP address in dotted
+    /// decimal notation, and `port` is the port number.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::SocketAddrV4;
+    /// use kernel::pr_info;
+    ///
+    /// let addr = SocketAddrV4::from_str("1.2.3.4:5678").unwrap();
+    /// pr_info!("{}", addr); // prints "1.2.3.4:5678"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is the length of 255.255.255.255:12345, the biggest SocketAddrV4 string.
+        unsafe {
+            write_addr::<{ SocketAddrV4::MAX_STRING_LEN + 1 }, SocketAddrV4>(
+                f,
+                c_str!("%pISpc"),
+                self,
+            )
+        }
+    }
+}
+
+impl Debug for SocketAddrV4 {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "SocketAddrV4({})", self)
+    }
+}
+
+impl FromStr for SocketAddrV4 {
+    type Err = Error;
+
+    /// Parses a string as an IPv4 socket address.
+    ///
+    /// The string must be in the form `a.b.c.d:p`, where `a`, `b`, `c`, `d` are the four
+    /// components of the IPv4 address, and `p` is the port.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddrV4};
+    ///
+    /// // valid
+    /// let addr = SocketAddrV4::from_str("192.168.1.0:80").unwrap();
+    /// assert_eq!(addr.ip(), &Ipv4Addr::new(192, 168, 1, 0));
+    /// assert_eq!(addr.port(), 80);
+    ///
+    /// // invalid
+    /// assert!(SocketAddrV4::from_str("192.168:800:80").is_err());
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let (addr, port) = s.split_once(':').ok_or(code::EINVAL)?;
+        address_from_string(addr, port, init_net())
+    }
+}
+
+impl Display for SocketAddrV6 {
+    /// Display the address as a string.
+    ///
+    /// The output string is of the form `[addr]:port`, where `addr` is an IPv6 address and `port`
+    /// is a port number.
+    ///
+    /// Flow info and scope ID are not supported and are excluded from the output.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// let addr = SocketAddrV6::from_str("[::1]:80").unwrap();
+    /// pr_info!("{}", addr);  // prints "[::1]:80"
+    /// ```
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        // SAFETY: MAX_STRING_LEN is big enough to hold the biggest SocketAddrV6 string.
+        unsafe {
+            write_addr::<{ SocketAddrV6::MAX_STRING_LEN + 1 }, SocketAddrV6>(
+                f,
+                c_str!("%pISpc"),
+                self,
+            )
+        }
+    }
+}
+
+impl Debug for SocketAddrV6 {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        write!(f, "SocketAddrV6({})", self)
+    }
+}
+
+impl FromStr for SocketAddrV6 {
+    type Err = Error;
+
+    /// Parses a string as an IPv6 socket address.
+    ///
+    /// The given string must be of the form `[addr]:port`, where `addr` is an IPv6 address and
+    /// `port` is a port number.
+    ///
+    /// Flow info and scope ID are not supported.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::addr::{Ipv6Addr, SocketAddrV6};
+    ///
+    /// // valid
+    /// let addr = SocketAddrV6::from_str("[2001:db8:85a3::8a2e:370:7334]:80").unwrap();
+    /// assert_eq!(addr.ip(), &Ipv6Addr::new(0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334));
+    /// assert_eq!(addr.port(), 80);
+    /// ```
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let (addr, port) = s.rsplit_once(':').ok_or(code::EINVAL)?;
+        let address = addr.trim_start_matches('[').trim_end_matches(']');
+        address_from_string(address, port, init_net())
+    }
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH 3/7] rust: net: add socket-related flags and flagset.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 1/7] rust: net: add net module files and shared enums Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 2/7] rust: net: add ip and socket address bindings Michele Dalle Rive
@ 2023-08-14  9:22 ` Michele Dalle Rive
  2023-08-14  9:22 ` [RFC PATCH 4/7] rust: net: add socket wrapper Michele Dalle Rive
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:22 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Add enums representing flags related to sockets:
- `ReceiveFlag` to modify the behaviour of the socket receive operation.
- `SendFlag` to modify the behaviour of the socket send operation.
- `MessageFlag` to represent the flags in a `msghdr`.
- `SocketFlag` to represent the flags in the `socket` struct.

Introduce a `FlagSet` structure to offer a convenient way to handle the
flags.
Having an abstraction over the "raw" numerical value of the flags offers
many advantages:
- A `FlagSet` can be created in different ways: from an `IntoIterator`,
  a value, a single flag or using the defined macro `flag_set!(...)`.
- Custom operations can be defined, such as the bitwise or.
- Flags in the set can be set, tested, unset through functions instead
  of using bitwise operations.
- FlagSet implements the IntoIterator trait, allowing for iteration over
  the flags contained.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
Opinions on FlagSet? I think it might be a convenient structure, for any
kind of "bitmask flag", not necessarily limited to the socket ones,
since it provides methods to easily create and access the flags.
However, it might be cumbersome to use to just obtain the same result of
a simple bitwise OR.

 rust/kernel/net/socket/flags.rs | 467 ++++++++++++++++++++++++++++++++
 1 file changed, 467 insertions(+)
 create mode 100644 rust/kernel/net/socket/flags.rs

diff --git a/rust/kernel/net/socket/flags.rs b/rust/kernel/net/socket/flags.rs
new file mode 100644
index 000000000000..fe98e09a8d46
--- /dev/null
+++ b/rust/kernel/net/socket/flags.rs
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Socket-related flags and utilities.
+use crate::bindings;
+use core::fmt::Debug;
+use core::ops::{BitOr, BitOrAssign};
+
+/// Generic socket flag trait.
+///
+/// This trait represents any kind of flag with "bitmask" values (i.e. 0x1, 0x2, 0x4, 0x8, etc.)
+pub trait Flag:
+    Into<isize> + TryFrom<isize> + Debug + Copy + Clone + Send + Sync + 'static
+{
+}
+
+/// Socket send operation flags.
+///
+/// See <https://linux.die.net/man/2/sendmsg> for more.
+#[derive(Debug, Copy, Clone)]
+pub enum SendFlag {
+    /// Got a successful reply.
+    ///
+    /// Only valid for datagram and raw sockets.
+    /// Only valid for IPv4 and IPv6.
+    Confirm = bindings::MSG_CONFIRM as isize,
+
+    /// Don't use a gateway to send out the packet.
+    DontRoute = bindings::MSG_DONTROUTE as isize,
+
+    /// Enables nonblocking operation.
+    ///
+    /// If the operation would block, return immediately with an error.
+    DontWait = bindings::MSG_DONTWAIT as isize,
+
+    /// Terminates a record.
+    EOR = bindings::MSG_EOR as isize,
+
+    /// More data will be sent.
+    ///
+    /// Only valid for TCP and UDP sockets.
+    More = bindings::MSG_MORE as isize,
+
+    /// Don't send SIGPIPE error if the socket is shut down.
+    NoSignal = bindings::MSG_NOSIGNAL as isize,
+
+    /// Send out-of-band data on supported sockets.
+    OOB = bindings::MSG_OOB as isize,
+}
+
+impl From<SendFlag> for isize {
+    fn from(value: SendFlag) -> Self {
+        value as isize
+    }
+}
+
+impl TryFrom<isize> for SendFlag {
+    type Error = ();
+
+    fn try_from(value: isize) -> Result<SendFlag, Self::Error> {
+        let val = value as u32;
+        match val {
+            bindings::MSG_CONFIRM => Ok(SendFlag::Confirm),
+            bindings::MSG_DONTROUTE => Ok(SendFlag::DontRoute),
+            bindings::MSG_DONTWAIT => Ok(SendFlag::DontWait),
+            bindings::MSG_EOR => Ok(SendFlag::EOR),
+            bindings::MSG_MORE => Ok(SendFlag::More),
+            bindings::MSG_NOSIGNAL => Ok(SendFlag::NoSignal),
+            bindings::MSG_OOB => Ok(SendFlag::OOB),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Flag for SendFlag {}
+
+/// Socket receive operation flags.
+///
+/// See <https://linux.die.net/man/2/recvmsg> for more.
+#[derive(Debug, Copy, Clone)]
+pub enum ReceiveFlag {
+    /// Enables nonblocking operation.
+    ///
+    /// If the operation would block, return immediately with an error.
+    DontWait = bindings::MSG_DONTWAIT as isize,
+
+    /// Specifies that queued errors should be received from the socket error queue.
+    ErrQueue = bindings::MSG_ERRQUEUE as isize,
+
+    /// Enables out-of-band reception.
+    OOB = bindings::MSG_OOB as isize,
+
+    /// Peeks at an incoming message.
+    ///
+    /// The data is treated as unread and the next recv() or similar function shall still return this data.
+    Peek = bindings::MSG_PEEK as isize,
+
+    /// Returns the real length of the packet, even when it was longer than the passed buffer.
+    ///
+    /// Only valid for raw, datagram, netlink and UNIX datagram sockets.
+    Trunc = bindings::MSG_TRUNC as isize,
+
+    /// Waits for the full request to be satisfied.
+    WaitAll = bindings::MSG_WAITALL as isize,
+}
+
+impl From<ReceiveFlag> for isize {
+    fn from(value: ReceiveFlag) -> Self {
+        value as isize
+    }
+}
+
+impl TryFrom<isize> for ReceiveFlag {
+    type Error = ();
+
+    fn try_from(value: isize) -> Result<Self, Self::Error> {
+        let val = value as u32;
+        match val {
+            bindings::MSG_DONTWAIT => Ok(ReceiveFlag::DontWait),
+            bindings::MSG_ERRQUEUE => Ok(ReceiveFlag::ErrQueue),
+            bindings::MSG_OOB => Ok(ReceiveFlag::OOB),
+            bindings::MSG_PEEK => Ok(ReceiveFlag::Peek),
+            bindings::MSG_TRUNC => Ok(ReceiveFlag::Trunc),
+            bindings::MSG_WAITALL => Ok(ReceiveFlag::WaitAll),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Flag for ReceiveFlag {}
+
+/// Socket `flags` field flags.
+///
+/// These flags are used internally by the kernel.
+/// However, they are exposed here for completeness.
+///
+/// This enum does not implement the `Flag` trait, since it is not actually a flag.
+/// Flags are often defined as a mask that can be used to retrieve the flag value; the socket flags,
+/// instead, are defined as the index of the bit that they occupy in the `flags` field.
+/// This means that they cannot be used as a mask, just like all the other flags that implement `Flag` do.
+///
+/// For example, SOCK_PASSCRED has value 3, meaning that it is represented by the 3rd bit of the `flags` field;
+/// a normal flag would represent it as a mask, i.e. 1 << 3 = 0b1000.
+///
+/// See [include/linux/net.h](../../../../include/linux/net.h) for more.
+pub enum SocketFlag {
+    /// Undocumented.
+    NoSpace = bindings::SOCK_NOSPACE as isize,
+    /// Undocumented.
+    PassCred = bindings::SOCK_PASSCRED as isize,
+    /// Undocumented.
+    PassSecurity = bindings::SOCK_PASSSEC as isize,
+    /// Undocumented.
+    SupportZeroCopy = bindings::SOCK_SUPPORT_ZC as isize,
+    /// Undocumented.
+    CustomSockOpt = bindings::SOCK_CUSTOM_SOCKOPT as isize,
+    /// Undocumented.
+    PassPidFd = bindings::SOCK_PASSPIDFD as isize,
+}
+
+impl From<SocketFlag> for isize {
+    fn from(value: SocketFlag) -> Self {
+        value as isize
+    }
+}
+
+impl TryFrom<isize> for SocketFlag {
+    type Error = ();
+
+    fn try_from(value: isize) -> Result<Self, Self::Error> {
+        let val = value as u32;
+        match val {
+            bindings::SOCK_NOSPACE => Ok(SocketFlag::NoSpace),
+            bindings::SOCK_PASSCRED => Ok(SocketFlag::PassCred),
+            bindings::SOCK_PASSSEC => Ok(SocketFlag::PassSecurity),
+            bindings::SOCK_SUPPORT_ZC => Ok(SocketFlag::SupportZeroCopy),
+            bindings::SOCK_CUSTOM_SOCKOPT => Ok(SocketFlag::CustomSockOpt),
+            bindings::SOCK_PASSPIDFD => Ok(SocketFlag::PassPidFd),
+            _ => Err(()),
+        }
+    }
+}
+
+/// Flags associated with a received message.
+///
+/// Represents the flag contained in the `msg_flags` field of a `msghdr` struct.
+#[derive(Debug, Copy, Clone)]
+pub enum MessageFlag {
+    /// End of record.
+    Eor = bindings::MSG_EOR as isize,
+    /// Trailing portion of the message is discarded.
+    Trunc = bindings::MSG_TRUNC as isize,
+    /// Control data was discarded due to lack of space.
+    Ctrunc = bindings::MSG_CTRUNC as isize,
+    /// Out-of-band data was received.
+    Oob = bindings::MSG_OOB as isize,
+    /// An error was received instead of data.
+    ErrQueue = bindings::MSG_ERRQUEUE as isize,
+}
+
+impl From<MessageFlag> for isize {
+    fn from(value: MessageFlag) -> Self {
+        value as isize
+    }
+}
+
+impl TryFrom<isize> for MessageFlag {
+    type Error = ();
+
+    fn try_from(value: isize) -> Result<Self, Self::Error> {
+        let val = value as u32;
+        match val {
+            bindings::MSG_EOR => Ok(MessageFlag::Eor),
+            bindings::MSG_TRUNC => Ok(MessageFlag::Trunc),
+            bindings::MSG_CTRUNC => Ok(MessageFlag::Ctrunc),
+            bindings::MSG_OOB => Ok(MessageFlag::Oob),
+            bindings::MSG_ERRQUEUE => Ok(MessageFlag::ErrQueue),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Flag for MessageFlag {}
+
+/// Structure representing a set of flags.
+///
+/// This structure is used to represent a set of flags, such as the flags passed to `send` or `recv`.
+/// It is generic over the type of flag that it contains.
+///
+/// # Invariants
+/// The value of the flags must be a valid combination of the flags that it contains.
+///
+/// This means that the value must be the bitwise OR of the values of the flags, and that it
+/// must be possible to retrieve the value of the flags from the value.
+///
+/// # Example
+/// ```
+/// use kernel::net::socket::flags::{SendFlag, FlagSet};
+///
+/// let mut flags = FlagSet::<SendFlag>::empty();
+/// flags.insert(SendFlag::DontWait);
+/// flags.insert(SendFlag::More);
+/// assert!(flags.contains(SendFlag::DontWait));
+/// assert!(flags.contains(SendFlag::More));
+/// flags.clear();
+/// assert_eq!(flags.value(), 0);
+///
+/// flags = FlagSet::<SendFlag>::from(SendFlag::More);
+/// flags |= SendFlag::DontWait;
+/// assert!(flags.contains(SendFlag::DontWait));
+/// ```
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct FlagSet<T: Flag> {
+    value: isize,
+    _phantom: core::marker::PhantomData<T>,
+}
+
+impl<T: Flag> FlagSet<T> {
+    /// Create a new empty set of flags.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::flags::{SendFlag, FlagSet};
+    ///
+    /// let flags = FlagSet::<SendFlag>::empty();
+    /// assert_eq!(flags.value(), 0);
+    /// ```
+    pub fn empty() -> Self {
+        FlagSet {
+            value: 0,
+            _phantom: core::marker::PhantomData,
+        }
+    }
+
+    /// Clear all the flags set.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::flags::{SendFlag, FlagSet};
+    ///
+    /// let mut flags = FlagSet::<SendFlag>::from(SendFlag::More);
+    /// assert!(flags.contains(SendFlag::More));
+    /// flags.clear();
+    /// assert_eq!(flags.value(), 0);
+    /// ```
+    pub fn clear(&mut self) {
+        self.value = 0;
+    }
+
+    /// Add a flag to the set.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::flags::{SendFlag, FlagSet};
+    ///
+    /// let mut flags = FlagSet::<SendFlag>::empty();
+    /// assert!(!flags.contains(SendFlag::DontWait));
+    /// flags.insert(SendFlag::DontWait);
+    /// assert!(flags.contains(SendFlag::DontWait));
+    /// ```
+    pub fn insert(&mut self, flag: T) {
+        self.value |= flag.into();
+    }
+
+    /// Remove a flag from the set.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::flags::{SendFlag, FlagSet};
+    ///
+    /// let mut flags = FlagSet::<SendFlag>::from(SendFlag::DontWait);
+    /// assert!(flags.contains(SendFlag::DontWait));
+    /// flags.remove(SendFlag::DontWait);
+    /// assert!(!flags.contains(SendFlag::DontWait));
+    /// ```
+    pub fn remove(&mut self, flag: T) {
+        self.value &= !flag.into();
+    }
+
+    /// Check if a flag is set.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::flags::{SendFlag, FlagSet};
+    ///
+    /// let mut flags = FlagSet::<SendFlag>::from(SendFlag::DontWait);
+    /// assert!(flags.contains(SendFlag::DontWait));
+    /// ```
+    pub fn contains(&self, flag: T) -> bool {
+        self.value & flag.into() != 0
+    }
+
+    /// Get the integer value of the flags set.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::flags::{SendFlag, FlagSet};
+    ///
+    /// let flags = FlagSet::<SendFlag>::from(SendFlag::DontWait);
+    /// assert_eq!(flags.value(), SendFlag::DontWait as isize);
+    /// ```
+    pub fn value(&self) -> isize {
+        self.value
+    }
+}
+
+impl<T: Flag> BitOr<T> for FlagSet<T> {
+    type Output = FlagSet<T>;
+
+    fn bitor(self, rhs: T) -> Self::Output {
+        FlagSet {
+            value: self.value | rhs.into(),
+            _phantom: core::marker::PhantomData,
+        }
+    }
+}
+
+impl<T: Flag> BitOrAssign<T> for FlagSet<T> {
+    fn bitor_assign(&mut self, rhs: T) {
+        self.value |= rhs.into();
+    }
+}
+
+// impl from isize for any flags<T>
+impl<T: Flag> From<isize> for FlagSet<T> {
+    fn from(value: isize) -> Self {
+        FlagSet {
+            value,
+            _phantom: core::marker::PhantomData,
+        }
+    }
+}
+
+impl<T: Flag> From<T> for FlagSet<T> {
+    fn from(value: T) -> Self {
+        Self::from(value.into())
+    }
+}
+
+impl<T: Flag> FromIterator<T> for FlagSet<T> {
+    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
+        let mut flags = FlagSet::empty();
+        for flag in iter {
+            flags.insert(flag);
+        }
+        flags
+    }
+}
+
+impl<T: Flag> From<FlagSet<T>> for isize {
+    fn from(value: FlagSet<T>) -> Self {
+        value.value
+    }
+}
+
+impl<T: Flag> IntoIterator for FlagSet<T> {
+    type Item = T;
+    type IntoIter = FlagSetIterator<T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        FlagSetIterator {
+            flags: self,
+            current: 0,
+        }
+    }
+}
+
+/// Iterator over the flags in a set.
+///
+/// This iterator iterates over the flags in a set, in order of increasing value.
+///
+/// # Example
+/// ```
+/// use kernel::net::socket::flags::{SendFlag, FlagSet};
+///
+/// let mut flags = FlagSet::from_iter([SendFlag::DontWait, SendFlag::More]);
+/// for flag in flags.into_iter() {
+///    println!("Flag: {:?}", flag);
+/// }
+/// ```
+pub struct FlagSetIterator<T: Flag> {
+    flags: FlagSet<T>,
+    current: usize,
+}
+
+impl<T: Flag> Iterator for FlagSetIterator<T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let mut value = 1 << self.current;
+        while value <= self.flags.value {
+            self.current += 1;
+            if self.flags.value & value != 0 {
+                if let Ok(flag) = T::try_from(value) {
+                    return Some(flag);
+                }
+            }
+            value = 1 << self.current;
+        }
+        None
+    }
+}
+
+/// Create a set of flags from a list of flags.
+///
+/// This macro provides a compact way to create empty sets and sets from a list of flags.
+///
+/// # Example
+/// ```
+/// use kernel::net::socket::flags::SendFlag;
+/// use kernel::flag_set;
+///
+/// let mut flags = flag_set!(SendFlag::DontWait, SendFlag::More);
+/// assert!(flags.contains(SendFlag::DontWait));
+/// assert!(flags.contains(SendFlag::More));
+///
+/// let mut empty_flags = flag_set!();
+/// assert_eq!(empty_flags.value(), 0);
+/// ```
+#[macro_export]
+macro_rules! flag_set {
+    () => {
+        $crate::net::socket::flags::FlagSet::empty()
+    };
+    ($($flag:expr),+) => {
+        $crate::net::socket::flags::FlagSet::from_iter([$($flag),+])
+    };
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH 4/7] rust: net: add socket wrapper.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
                   ` (2 preceding siblings ...)
  2023-08-14  9:22 ` [RFC PATCH 3/7] rust: net: add socket-related flags and flagset Michele Dalle Rive
@ 2023-08-14  9:22 ` Michele Dalle Rive
  2023-08-14  9:23 ` [RFC PATCH 5/7] rust: net: implement socket options API Michele Dalle Rive
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:22 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Create a `Socket` abstraction, which provides a Rust API to the kernel
socket functionalities.

The Socket structures tries to keep the same function signatures of the
Rust standard library; at the same time, functions are added or modified
in order to provide as much as possible of the C kernel functionalities.

Most of the internals of the C socket is not accessible by Rust, because
those structures are still to be wrapped. However, sockets are mainly
managed through the functions provided by the kernel; thus, even if some
fields are not accessible, since the functions are wrapped, most of the 
kernel functionality should be available in Rust as well.

Specifically, the usage of `msghdr` is mostly abstracted away in the
Rust interface, because using it would mean having to deal, both in the
kernel and in modules, with Pinned instances (msghdr is self-referencing),
which would be a struggle that provides no particular advantage.
A `MessageHeader` object is actually created and returned when a message
is received, because at that point the structure is not really
self-referencing, as long as the source address is copied. The wrapper
is not used when a message is sent.
Anyways, some useful functionalities of `msghdr`, like `cmsghdr`s, are 
missing and should be implemented in the future to provide a complete API.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
Few questions here as well:
- What about `MessageHeader`? Does it make sense to only have it on a
  receive? My reasoning was that, AFAIK, when sending a message, the
  `msghdr` structure is used for the flags and for eventually the
  destination address. Does it make sense having to handle a pinned
  object just to avoid having flags and destination address as arguments
  of the send function? When a message is received, instead, there is no
  pinning problem (as long as the address is saved), so the message
  header can be freely returned and handled. As of now, the
  `MessageHeader` only contains sender address and flags, but in the
  future more `msghdr` fields could be wrapped.
- In `has_flag` and `set_flag`, does it make sense to use the
  bindgen-provided `__BindgenBitfieldUnit`? It is particularly
  convenient, as it handles the big/little endianness. However, I
  noticed that it changes between different bindgen version, and keeping
  the code up to date could take more time than manually handle the
  endianness.

 rust/kernel/net.rs        |   1 +
 rust/kernel/net/socket.rs | 550 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 551 insertions(+)
 create mode 100644 rust/kernel/net/socket.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index 346e7374e614..7d58ebb0324f 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -12,6 +12,7 @@
 
 pub mod addr;
 pub mod ip;
+pub mod socket;
 
 /// The address family.
 ///
diff --git a/rust/kernel/net/socket.rs b/rust/kernel/net/socket.rs
new file mode 100644
index 000000000000..8396ce4b83a8
--- /dev/null
+++ b/rust/kernel/net/socket.rs
@@ -0,0 +1,550 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Socket API.
+//!
+//! This module contains the Socket layer kernel APIs that have been wrapped for usage by Rust code
+//! in the kernel.
+//!
+//! C header: [`include/linux/socket.h`](../../../../include/linux/socket.h)
+//!
+//! This API is inspired by the Rust std::net Socket API, but is not a direct port.
+//! The main difference is that the Rust std::net API is designed for user-space, while this API
+//! is designed for kernel-space.
+//! Rust net API: <https://doc.rust-lang.org/std/net/index.html>
+
+use super::*;
+use crate::error::{to_result, Result};
+use crate::net::addr::*;
+use crate::net::ip::IpProtocol;
+use flags::*;
+
+pub mod flags;
+
+/// The socket type.
+pub enum SockType {
+    /// Stream socket (e.g. TCP)
+    Stream = bindings::sock_type_SOCK_STREAM as isize,
+    /// Connectionless socket (e.g. UDP)
+    Datagram = bindings::sock_type_SOCK_DGRAM as isize,
+    /// Raw socket
+    Raw = bindings::sock_type_SOCK_RAW as isize,
+    /// Reliably-delivered message
+    Rdm = bindings::sock_type_SOCK_RDM as isize,
+    /// Sequenced packet stream
+    Seqpacket = bindings::sock_type_SOCK_SEQPACKET as isize,
+    /// Datagram Congestion Control Protocol socket
+    Dccp = bindings::sock_type_SOCK_DCCP as isize,
+    /// Packet socket
+    Packet = bindings::sock_type_SOCK_PACKET as isize,
+}
+
+/// The socket shutdown command.
+pub enum ShutdownCmd {
+    /// Disallow further receive operations.
+    Read = bindings::sock_shutdown_cmd_SHUT_RD as isize,
+    /// Disallow further send operations.
+    Write = bindings::sock_shutdown_cmd_SHUT_WR as isize,
+    /// Disallow further send and receive operations.
+    Both = bindings::sock_shutdown_cmd_SHUT_RDWR as isize,
+}
+
+/// A generic socket.
+///
+/// Wraps a `struct socket` from the kernel.
+/// See [include/linux/socket.h](../../../../include/linux/socket.h) for more information.
+///
+/// The wrapper offers high-level methods for common operations on the socket.
+/// More fine-grained control is possible by using the C bindings directly.
+///
+/// # Example
+/// A simple TCP echo server:
+/// ```rust
+/// use kernel::flag_set;
+/// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+/// use kernel::net::{AddressFamily, init_net};
+/// use kernel::net::ip::IpProtocol;
+/// use kernel::net::socket::{Socket, SockType};
+///
+/// let socket = Socket::new_kern(
+///     init_net(),
+///     AddressFamily::Inet,
+///     SockType::Stream,
+///     IpProtocol::Tcp,
+/// )?;
+/// socket.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000)))?;
+/// socket.listen(10)?;
+/// while let Ok(peer) = socket.accept(true) {
+///     let mut buf = [0u8; 1024];
+///     peer.receive(&mut buf, flag_set!())?;
+///     peer.send(&buf, flag_set!())?;
+/// }
+/// ```
+/// A simple UDP echo server:
+/// ```rust
+/// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+/// use kernel::net::{AddressFamily, init_net};
+/// use kernel::net::ip::IpProtocol;
+/// use kernel::net::socket::{Socket, SockType};
+/// use kernel::flag_set;
+///
+/// let socket = Socket::new_kern(init_net(), AddressFamily::Inet, SockType::Datagram, IpProtocol::Udp)?;///
+/// socket.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000)))?;
+/// let mut buf = [0u8; 1024];
+/// while let Ok((len, sender_opt)) = socket.receive_from(&mut buf, flag_set!()) {
+///     let sender: SocketAddr = sender_opt.expect("Sender address is always available for UDP");
+///     socket.send_to(&buf[..len], &sender, flag_set!())?;
+/// }
+/// ```
+///
+/// # Invariants
+///
+/// The socket pointer is valid for the lifetime of the wrapper.
+#[repr(transparent)]
+pub struct Socket(*mut bindings::socket);
+
+/// Getters and setters of socket internal fields.
+///
+/// Not all fields are currently supported: hopefully, this will be improved in the future.
+impl Socket {
+    /// Retrieve the flags associated with the socket.
+    ///
+    /// Unfortunately, these flags cannot be represented as a [`FlagSet`], since [`SocketFlag`]s
+    /// are not represented as masks but as the index of the bit they represent.
+    ///
+    /// An enum could be created, containing masks instead of indexes, but this could create
+    /// confusion with the C side.
+    ///
+    /// The methods [`Socket::has_flag`] and [`Socket::set_flags`] can be used to check and set individual flags.
+    pub fn flags(&self) -> u64 {
+        unsafe { (*self.0).flags }
+    }
+
+    /// Set the flags associated with the socket.
+    pub fn set_flags(&self, flags: u64) {
+        unsafe {
+            (*self.0).flags = flags;
+        }
+    }
+
+    /// Checks if the socket has a specific flag.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::{Socket, flags::SocketFlag, SockType};
+    /// use kernel::net::AddressFamily;
+    /// use kernel::net::ip::IpProtocol;
+    ///
+    /// let socket = Socket::new(AddressFamily::Inet, SockType::Datagram, IpProtocol::Udp)?;
+    /// assert_eq!(socket.has_flag(SocketFlag::CustomSockOpt), false);
+    /// ```
+    pub fn has_flag(&self, flag: SocketFlag) -> bool {
+        bindings::__BindgenBitfieldUnit::<[u8; 8], u8>::new(self.flags().to_be_bytes())
+            .get_bit(flag as _)
+    }
+
+    /// Sets a flag on the socket.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::{Socket, flags::SocketFlag, SockType};
+    /// use kernel::net::AddressFamily;
+    /// use kernel::net::ip::IpProtocol;
+    ///
+    /// let socket = Socket::new(AddressFamily::Inet, SockType::Datagram, IpProtocol::Udp)?;
+    /// assert_eq!(socket.has_flag(SocketFlag::CustomSockOpt), false);
+    /// socket.set_flag(SocketFlag::CustomSockOpt, true);
+    /// assert_eq!(socket.has_flag(SocketFlag::CustomSockOpt), true);
+    /// ```
+    pub fn set_flag(&self, flag: SocketFlag, value: bool) {
+        let flags_width = core::mem::size_of_val(&self.flags()) * 8;
+        let mut flags =
+            bindings::__BindgenBitfieldUnit::<[u8; 8], u8>::new(self.flags().to_be_bytes());
+        flags.set_bit(flag as _, value);
+        self.set_flags(flags.get(0, flags_width as _));
+    }
+
+    /// Consumes the socket and returns the underlying pointer.
+    ///
+    /// The pointer is valid for the lifetime of the wrapper.
+    ///
+    /// # Safety
+    /// The caller must ensure that the pointer is not used after the wrapper is dropped.
+    pub unsafe fn into_inner(self) -> *mut bindings::socket {
+        self.0
+    }
+
+    /// Returns the underlying pointer.
+    ///
+    /// The pointer is valid for the lifetime of the wrapper.
+    ///
+    /// # Safety
+    /// The caller must ensure that the pointer is not used after the wrapper is dropped.
+    pub unsafe fn as_inner(&self) -> *mut bindings::socket {
+        self.0
+    }
+}
+
+/// Socket API implementation
+impl Socket {
+    /// Private utility function to create a new socket by calling a function.
+    /// The function is generic over the creation function.
+    ///
+    /// # Arguments
+    /// * `create_fn`: A function that initiates the socket given as parameter.
+    ///                The function must return 0 on success and a negative error code on failure.
+    fn base_new<T>(create_fn: T) -> Result<Self>
+    where
+        T: (FnOnce(*mut *mut bindings::socket) -> core::ffi::c_int),
+    {
+        let mut socket_ptr: *mut bindings::socket = core::ptr::null_mut();
+        to_result(create_fn(&mut socket_ptr))?;
+        Ok(Self(socket_ptr))
+    }
+
+    /// Create a new socket.
+    ///
+    /// Wraps the `sock_create` function.
+    pub fn new(family: AddressFamily, type_: SockType, proto: IpProtocol) -> Result<Self> {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        Self::base_new(|socket_ptr| unsafe {
+            bindings::sock_create(family as _, type_ as _, proto as _, socket_ptr)
+        })
+    }
+
+    /// Create a new socket in a specific namespace.
+    ///
+    /// Wraps the `sock_create_kern` function.
+    pub fn new_kern(
+        ns: &Namespace,
+        family: AddressFamily,
+        type_: SockType,
+        proto: IpProtocol,
+    ) -> Result<Self> {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        Self::base_new(|socket_ptr| unsafe {
+            bindings::sock_create_kern(ns.0.get(), family as _, type_ as _, proto as _, socket_ptr)
+        })
+    }
+
+    /// Creates a new "lite" socket.
+    ///
+    /// Wraps the `sock_create_lite` function.
+    ///
+    /// This is a lighter version of `sock_create` that does not perform any sanity check.
+    pub fn new_lite(family: AddressFamily, type_: SockType, proto: IpProtocol) -> Result<Self> {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        Self::base_new(|socket_ptr| unsafe {
+            bindings::sock_create_lite(family as _, type_ as _, proto as _, socket_ptr)
+        })
+    }
+
+    /// Binds the socket to a specific address.
+    ///
+    /// Wraps the `kernel_bind` function.
+    pub fn bind(&self, address: SocketAddr) -> Result {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        to_result(unsafe {
+            bindings::kernel_bind(self.0, address.as_ptr() as _, address.size() as i32)
+        })
+    }
+
+    /// Connects the socket to a specific address.
+    ///
+    /// Wraps the `kernel_connect` function.
+    ///
+    /// The socket must be a connection-oriented socket.
+    /// If the socket is not bound, it will be bound to a random local address.
+    ///
+    /// # Example
+    /// ```rust
+    /// use kernel::net::{AddressFamily, init_net};
+    /// use kernel::net::addr::{Ipv4Addr, SocketAddr, SocketAddrV4};
+    /// use kernel::net::ip::IpProtocol;
+    /// use kernel::net::socket::{Socket, SockType};
+    ///
+    /// let socket = Socket::new_kern(init_net(), AddressFamily::Inet, SockType::Stream, IpProtocol::Tcp)?;
+    /// socket.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000)))?;
+    /// socket.listen(10)?;
+    pub fn listen(&self, backlog: i32) -> Result {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        to_result(unsafe { bindings::kernel_listen(self.0, backlog) })
+    }
+
+    /// Accepts a connection on a socket.
+    ///
+    /// Wraps the `kernel_accept` function.
+    pub fn accept(&self, block: bool) -> Result<Socket> {
+        let mut new_sock = core::ptr::null_mut();
+        let flags: i32 = if block { 0 } else { bindings::O_NONBLOCK as _ };
+
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        to_result(unsafe { bindings::kernel_accept(self.0, &mut new_sock, flags as _) })?;
+
+        Ok(Self(new_sock))
+    }
+
+    /// Returns the address the socket is bound to.
+    ///
+    /// Wraps the `kernel_getsockname` function.
+    pub fn sockname(&self) -> Result<SocketAddr> {
+        let mut addr: SocketAddrStorage = SocketAddrStorage::default();
+
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        unsafe {
+            to_result(bindings::kernel_getsockname(
+                self.0,
+                &mut addr as *mut _ as _,
+            ))
+        }
+        .and_then(|_| SocketAddr::try_from_raw(addr))
+    }
+
+    /// Returns the address the socket is connected to.
+    ///
+    /// Wraps the `kernel_getpeername` function.
+    ///
+    /// The socket must be connected.
+    pub fn peername(&self) -> Result<SocketAddr> {
+        let mut addr: SocketAddrStorage = SocketAddrStorage::default();
+
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        unsafe {
+            to_result(bindings::kernel_getpeername(
+                self.0,
+                &mut addr as *mut _ as _,
+            ))
+        }
+        .and_then(|_| SocketAddr::try_from_raw(addr))
+    }
+
+    /// Connects the socket to a specific address.
+    ///
+    /// Wraps the `kernel_connect` function.
+    pub fn connect(&self, address: &SocketAddr, flags: i32) -> Result {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        unsafe {
+            to_result(bindings::kernel_connect(
+                self.0,
+                address.as_ptr() as _,
+                address.size() as _,
+                flags,
+            ))
+        }
+    }
+
+    /// Shuts down the socket.
+    ///
+    /// Wraps the `kernel_sock_shutdown` function.
+    pub fn shutdown(&self, how: ShutdownCmd) -> Result {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        unsafe { to_result(bindings::kernel_sock_shutdown(self.0, how as _)) }
+    }
+
+    /// Receive a message from the socket.
+    ///
+    /// This function is the lowest-level receive function. It is used by the other receive functions.
+    ///
+    /// The `flags` parameter is a set of flags that control the behavior of the function.
+    /// The flags are described in the [`ReceiveFlag`] enum.
+    ///
+    /// The returned Message is a wrapper for `msghdr` and it contains the header information about the message,
+    /// including the sender address (if present) and the flags.
+    ///
+    /// The data message is written to the provided buffer and the number of bytes written is returned together with the header.
+    ///
+    /// Wraps the `kernel_recvmsg` function.
+    pub fn receive_msg(
+        &self,
+        bytes: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, MessageHeader)> {
+        let addr = SocketAddrStorage::default();
+
+        let mut msg = bindings::msghdr {
+            msg_name: &addr as *const _ as _,
+            ..Default::default()
+        };
+
+        let mut vec = bindings::kvec {
+            iov_base: bytes.as_mut_ptr() as _,
+            iov_len: bytes.len() as _,
+        };
+
+        // SAFETY: FFI call; the socket address is valid for the lifetime of the wrapper.
+        let size = unsafe {
+            bindings::kernel_recvmsg(
+                self.0,
+                &mut msg as _,
+                &mut vec,
+                1,
+                bytes.len() as _,
+                flags.value() as _,
+            )
+        };
+        to_result(size)?;
+
+        let addr: Option<SocketAddr> = SocketAddr::try_from_raw(addr).ok();
+
+        Ok((size as _, MessageHeader::new(msg, addr)))
+    }
+
+    /// Receives data from a remote socket and returns the bytes read and the sender address.
+    ///
+    /// Used by connectionless sockets to retrieve the sender of the message.
+    /// If the socket is connection-oriented, the sender address will be `None`.
+    ///
+    /// The function abstracts the usage of the `struct msghdr` type.
+    /// See [Socket::receive_msg] for more information.
+    pub fn receive_from(
+        &self,
+        bytes: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, Option<SocketAddr>)> {
+        self.receive_msg(bytes, flags)
+            .map(|(size, hdr)| (size, hdr.into()))
+    }
+
+    /// Receives data from a remote socket and returns only the bytes read.
+    ///
+    /// Used by connection-oriented sockets, where the sender address is the connected peer.
+    pub fn receive(&self, bytes: &mut [u8], flags: FlagSet<ReceiveFlag>) -> Result<usize> {
+        let (size, _) = self.receive_from(bytes, flags)?;
+        Ok(size)
+    }
+
+    /// Sends a message to a remote socket.
+    ///
+    /// Wraps the `kernel_sendmsg` function.
+    ///
+    /// Crate-public to allow its usage only in the kernel crate.
+    /// In the future, this function could be made public, accepting a [`Message`] as input,
+    /// but with the current API, it does not give any advantage.
+    pub(crate) fn send_msg(
+        &self,
+        bytes: &[u8],
+        mut message: bindings::msghdr,
+        flags: FlagSet<SendFlag>,
+    ) -> Result<usize> {
+        let mut vec = bindings::kvec {
+            iov_base: bytes.as_ptr() as _,
+            iov_len: bytes.len() as _,
+        };
+        message.msg_flags = flags.value() as _;
+
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        let size = unsafe {
+            bindings::kernel_sendmsg(
+                self.0,
+                &message as *const _ as _,
+                &mut vec,
+                1,
+                bytes.len() as _,
+            )
+        };
+        to_result(size)?;
+        Ok(size as _)
+    }
+
+    /// Sends a message to a remote socket and returns the bytes sent.
+    ///
+    /// The `flags` parameter is a set of flags that control the behavior of the function.
+    /// The flags are described in the [`SendFlag`] enum.
+    pub fn send(&self, bytes: &[u8], flags: FlagSet<SendFlag>) -> Result<usize> {
+        self.send_msg(bytes, bindings::msghdr::default(), flags)
+    }
+
+    /// Sends a message to a specific remote socket address and returns the bytes sent.
+    ///
+    /// The `flags` parameter is a set of flags that control the behavior of the function.
+    /// The flags are described in the [`SendFlag`] enum.
+    pub fn send_to(
+        &self,
+        bytes: &[u8],
+        address: &SocketAddr,
+        flags: FlagSet<SendFlag>,
+    ) -> Result<usize> {
+        let message = bindings::msghdr {
+            msg_name: address.as_ptr() as _,
+            msg_namelen: address.size() as _,
+            ..Default::default()
+        };
+        self.send_msg(bytes, message, flags)
+    }
+}
+
+impl Drop for Socket {
+    /// Closes and releases the socket.
+    ///
+    /// Wraps the `sock_release` function.
+    fn drop(&mut self) {
+        // SAFETY: FFI call; the address is valid for the lifetime of the wrapper.
+        unsafe {
+            bindings::sock_release(self.0);
+        }
+    }
+}
+
+// SAFETY: sockets are thread-safe; synchronization is handled by the kernel.
+unsafe impl Send for Socket {}
+unsafe impl Sync for Socket {}
+
+/// Socket header message.
+///
+/// Wraps the `msghdr` structure.
+/// This struct provides a safe interface to the `msghdr` structure.
+///
+/// The instances of this struct are only created by the `receive` methods of the [`Socket`] struct.
+///
+/// # Invariants
+/// The `msg_name` in the wrapped `msghdr` object is always null; the address is stored in the `MessageHeader` object
+/// and can be retrieved with the [`MessageHeader::address`] method.
+#[derive(Clone, Copy)]
+pub struct MessageHeader(pub(crate) bindings::msghdr, pub(crate) Option<SocketAddr>);
+
+impl MessageHeader {
+    /// Returns the address of the message.
+    pub fn address(&self) -> Option<&SocketAddr> {
+        self.1.as_ref()
+    }
+
+    /// Returns the flags of the message.
+    pub fn flags(&self) -> FlagSet<MessageFlag> {
+        FlagSet::from(self.0.msg_flags as isize)
+    }
+
+    /// Consumes the message header and returns the underlying `msghdr` structure.
+    ///
+    /// The returned msghdr will have a null pointer for the address.
+    pub fn into_raw(self) -> bindings::msghdr {
+        self.0
+    }
+
+    /// Creates a new message header.
+    ///
+    /// The `msg_name` of the field gets replaced with a NULL pointer.
+    pub(crate) fn new(mut hdr: bindings::msghdr, addr: Option<SocketAddr>) -> Self {
+        hdr.msg_name = core::ptr::null_mut();
+        Self(hdr, addr)
+    }
+}
+
+impl From<MessageHeader> for Option<SocketAddr> {
+    /// Consumes the message header and returns the contained address.
+    fn from(hdr: MessageHeader) -> Self {
+        hdr.1
+    }
+}
+
+impl From<MessageHeader> for bindings::msghdr {
+    /// Consumes the message header and returns the underlying `msghdr` structure.
+    ///
+    /// The returned msghdr will have a null pointer for the address.
+    ///
+    /// This function is actually supposed to be crate-public, since bindings are not supposed to be
+    /// used outside the kernel library.
+    /// However, until the support for `msghdr` is not complete, specific needs might be satisfied
+    /// only by using directly the underlying `msghdr` structure.
+    fn from(hdr: MessageHeader) -> Self {
+        hdr.0
+    }
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH 5/7] rust: net: implement socket options API.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
                   ` (3 preceding siblings ...)
  2023-08-14  9:22 ` [RFC PATCH 4/7] rust: net: add socket wrapper Michele Dalle Rive
@ 2023-08-14  9:23 ` Michele Dalle Rive
  2023-08-14  9:23 ` [RFC PATCH 6/7] rust: net: add socket TCP wrappers Michele Dalle Rive
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:23 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Create socket `Option`s and `set_option` function in the `Socket`
abstraction.

These changes introduce wrappers and functions to handle socket options
in Rust, with compilation-time advantages compared to the C API:
- Type safety: A specific option accepts only a value of the correct
  type.
- Read/write safety: A read-only option cannot be set.
- Coherence safety: An option of, for example, IP level cannot be set by
  specifying another level.

The downside of using options in the kernel is the lack of functions to
get the value of an option. For this reason, in Rust, kernel options can
only be set, but not retrieved.

Everything that can be done by socket options can actually be done
through helper functions, or by accessing directly the specific fields.
However, since the Rust-wrapped structures are few, it can be useful to
have options in order to still be able to modify the behaviour of the
socket.

As specified in the documentation of `opts.rs`, options could (and
should) be removed when the Rust API will be developed enough.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
Does this even make sense? I have been struggling figuring out whether
having socket options is reasonable.
As described in the message, I think that even if it just limited to
setting options, it could be useful: Rust support is very limited, and
having some freedom over the socket is better than having none.

Now, does the implementation make sense? If I had to implement options I
wanted to at least make the most out of Rust, trying to make them
type-safe and "read/write" safe. The result is effective for sure, but
the code might end up being a bit ugly. I preferred using a macro to 
implement the code, because implementing each trait for each option
would have been a huge amount of repeated code.

 rust/kernel/net/socket.rs      |   91 +++
 rust/kernel/net/socket/opts.rs | 1222 ++++++++++++++++++++++++++++++++
 2 files changed, 1313 insertions(+)
 create mode 100644 rust/kernel/net/socket/opts.rs

diff --git a/rust/kernel/net/socket.rs b/rust/kernel/net/socket.rs
index 8396ce4b83a8..1a7b3f7d8fc0 100644
--- a/rust/kernel/net/socket.rs
+++ b/rust/kernel/net/socket.rs
@@ -16,9 +16,14 @@
 use crate::error::{to_result, Result};
 use crate::net::addr::*;
 use crate::net::ip::IpProtocol;
+use crate::net::socket::opts::{OptionsLevel, WritableOption};
+use core::cmp::max;
+use core::marker::PhantomData;
 use flags::*;
+use kernel::net::socket::opts::SocketOption;
 
 pub mod flags;
+pub mod opts;
 
 /// The socket type.
 pub enum SockType {
@@ -470,6 +475,72 @@ pub fn send_to(
         };
         self.send_msg(bytes, message, flags)
     }
+
+    /// Sets an option on the socket.
+    ///
+    /// Wraps the `sock_setsockopt` function.
+    ///
+    /// The generic type `T` is the type of the option value.
+    /// See the [options module](opts) for the type and extra information about each option.
+    ///
+    /// Unfortunately, options can only be set but not retrieved.
+    /// This is because the kernel functions to retrieve options are not exported by the kernel.
+    /// The only exported functions accept user-space pointers, and are therefore not usable in the kernel.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::AddressFamily;
+    /// use kernel::net::ip::IpProtocol;use kernel::net::socket::{Socket, SockType};
+    /// use kernel::net::socket::opts;
+    ///
+    /// let socket = Socket::new(AddressFamily::Inet, SockType::Datagram, IpProtocol::Udp)?;
+    /// socket.set_option::<opts::ip::BindAddressNoPort>(true)?;
+    /// ```
+    pub fn set_option<O>(&self, value: impl Into<O::Type>) -> Result
+    where
+        O: SocketOption + WritableOption,
+    {
+        let value_ptr = SockPtr::new(&value);
+
+        // The minimum size is the size of an integer.
+        let min_size = core::mem::size_of::<core::ffi::c_int>();
+        let size = max(core::mem::size_of::<O::Type>(), min_size);
+
+        if O::level() == OptionsLevel::Socket && !self.has_flag(SocketFlag::CustomSockOpt) {
+            // SAFETY: FFI call;
+            // the address is valid for the lifetime of the wrapper;
+            // the size is at least the size of an integer;
+            // the level and name of the option are valid and coherent.
+            to_result(unsafe {
+                bindings::sock_setsockopt(
+                    self.0,
+                    O::level() as isize as _,
+                    O::value() as _,
+                    value_ptr.to_raw() as _,
+                    size as _,
+                )
+            })
+        } else {
+            // SAFETY: FFI call;
+            // the address is valid for the lifetime of the wrapper;
+            // the size is at least the size of an integer;
+            // the level and name of the option are valid and coherent.
+            to_result(unsafe {
+                (*(*self.0).ops)
+                    .setsockopt
+                    .map(|f| {
+                        f(
+                            self.0,
+                            O::level() as _,
+                            O::value() as _,
+                            value_ptr.to_raw() as _,
+                            size as _,
+                        )
+                    })
+                    .unwrap_or(-(bindings::EOPNOTSUPP as i32))
+            })
+        }
+    }
 }
 
 impl Drop for Socket {
@@ -548,3 +619,23 @@ fn from(hdr: MessageHeader) -> Self {
         hdr.0
     }
 }
+
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+struct SockPtr<'a>(bindings::sockptr_t, PhantomData<&'a ()>);
+
+impl<'a> SockPtr<'a> {
+    fn new<T>(value: &'a T) -> Self
+    where
+        T: Sized,
+    {
+        let mut sockptr = bindings::sockptr_t::default();
+        sockptr.__bindgen_anon_1.kernel = value as *const T as _;
+        sockptr._bitfield_1 = bindings::__BindgenBitfieldUnit::new([1; 1usize]); // kernel ptr
+        SockPtr(sockptr, PhantomData)
+    }
+
+    fn to_raw(self) -> bindings::sockptr_t {
+        self.0
+    }
+}
diff --git a/rust/kernel/net/socket/opts.rs b/rust/kernel/net/socket/opts.rs
new file mode 100644
index 000000000000..6ca8ac35b305
--- /dev/null
+++ b/rust/kernel/net/socket/opts.rs
@@ -0,0 +1,1222 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Socket options.
+//!
+//! This module contains the types related to socket options.
+//! It is meant to be used together with the [`Socket`](kernel::net::socket::Socket) type.
+//!
+//! Socket options have more sense in the user space than in the kernel space: the kernel can
+//! directly access the socket data structures, so it does not need to use socket options.
+//! However, that level of freedom is currently not available in the Rust kernel API; therefore,
+//! having socket options is a good compromise.
+//!
+//! When Rust wrappers for the structures related to the socket (and required by the options,
+//! e.g. `tcp_sock`, `inet_sock`, etc.) are available, the socket options will be removed,
+//! and substituted by direct methods inside the socket types.
+
+use kernel::bindings;
+
+/// Options level to retrieve and set socket options.
+/// See `man 7 socket` for more information.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum OptionsLevel {
+    /// IP level socket options.
+    /// See `man 7 ip` for more information.
+    Ip = bindings::IPPROTO_IP as isize,
+
+    /// Socket level socket options.
+    /// See `man 7 socket` for more information.
+    Socket = bindings::SOL_SOCKET as isize,
+
+    /// IPv6 level socket options.
+    /// See `man 7 ipv6` for more information.
+    Ipv6 = bindings::IPPROTO_IPV6 as isize,
+
+    /// Raw level socket options.
+    /// See `man 7 raw` for more information.
+    Raw = bindings::IPPROTO_RAW as isize,
+
+    /// TCP level socket options.
+    /// See `man 7 tcp` for more information.
+    Tcp = bindings::IPPROTO_TCP as isize,
+}
+
+/// Generic socket option type.
+///
+/// This trait is implemented by each individual socket option.
+///
+/// Having socket options as structs instead of enums allows:
+/// - Type safety, making sure that the correct type is used for each option.
+/// - Read/write enforcement, making sure that only readable options
+/// are read and only writable options are written.
+pub trait SocketOption {
+    /// Rust type of the option value.
+    ///
+    /// This type is used to store the value of the option.
+    /// It is also used to enforce type safety.
+    ///
+    /// For example, the [`ip::Mtu`] option has a value of type `u32`.
+    type Type;
+
+    /// Retrieve the C value of the option.
+    ///
+    /// This value is used to pass the option to the kernel.
+    fn value() -> isize;
+
+    /// Retrieve the level of the option.
+    ///
+    /// This value is used to pass the option to the kernel.
+    fn level() -> OptionsLevel;
+}
+
+/// Generic readable socket option type.
+///
+/// This trait is implemented by each individual readable socket option.
+/// Can be combined with [`WritableOption`] to create a readable and writable socket option.
+pub trait WritableOption: SocketOption {}
+
+/// Generic writable socket option type.
+///
+/// This trait is implemented by each individual writable socket option.
+/// Can be combined with [`ReadableOption`] to create a readable and writable socket option.
+pub trait ReadableOption: SocketOption {}
+
+/// Generates the code for the implementation of a socket option.
+///
+/// # Parameters
+/// * `$opt`: Name of the socket option.
+/// * `$value`: C value of the socket option.
+/// * `$level`: Level of the socket option, like [`OptionsLevel::Ip`].
+/// * `$rtyp`: Rust type of the socket option.
+/// * `$($tr:ty),*`: Traits that the socket option implements, like [`WritableOption`].
+macro_rules! impl_opt {
+    ($(#[$meta:meta])*
+    $opt:ident = $value:expr,
+    $level:expr,
+    unimplemented,
+    $($tr:ty),*) => {};
+
+    ($(#[$meta:meta])*
+    $opt:ident = $value:expr,
+    $level:expr,
+    $rtyp:ty,
+    $($tr:ty),*) => {
+        $(#[$meta])*
+        #[repr(transparent)]
+        #[derive(Default)]
+        pub struct $opt;
+        impl SocketOption for $opt {
+            type Type = $rtyp;
+            fn value() -> isize {
+                $value as isize
+            }
+            fn level() -> OptionsLevel {
+                $level
+            }
+        }
+        $(
+            impl $tr for $opt {}
+        )*
+    };
+}
+
+pub mod ip {
+    //! IP socket options.
+    use super::{OptionsLevel, ReadableOption, SocketOption, WritableOption};
+    use crate::net::addr::Ipv4Addr;
+
+    macro_rules! impl_ip_opt {
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        unimplemented,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Ip,
+                unimplemented,
+                $($tr),*
+            );
+        };
+
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        $rtyp:ty,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Ip,
+                $rtyp,
+                $($tr),*
+            );
+        };
+    }
+
+    impl_ip_opt!(
+        /// Join a multicast group.
+        ///
+        /// C value type: `struct ip_mreqn`.
+        AddMembership = bindings::IP_ADD_MEMBERSHIP,
+        unimplemented,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Join a multicast group with source filtering.
+        ///
+        /// C value type: `struct ip_mreq_source`
+        AddSourceMembership = bindings::IP_ADD_SOURCE_MEMBERSHIP,
+        unimplemented,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Don't reserve a port when binding with port number 0.
+        ///
+        /// C value type: `int`
+        BindAddressNoPort = bindings::IP_BIND_ADDRESS_NO_PORT,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Block packets from a specific source.
+        ///
+        /// C value type: `struct ip_mreq_source`
+        BlockSource = bindings::IP_BLOCK_SOURCE,
+        unimplemented,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Leave a multicast group.
+        ///
+        /// C value type: `struct ip_mreqn`
+        DropMembership = bindings::IP_DROP_MEMBERSHIP,
+        unimplemented,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Stop receiving packets from a specific source.
+        ///
+        /// C value type: `struct ip_mreq_source`
+        DropSourceMembership = bindings::IP_DROP_SOURCE_MEMBERSHIP,
+        unimplemented,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Allow binding to a non-local address.
+        ///
+        /// C value type: `int`
+        FreeBind = bindings::IP_FREEBIND,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Receive the IP header with the packet.
+        ///
+        /// C value type: `int`
+        Header = bindings::IP_HDRINCL,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Full-state multicast filtering API.
+        ///
+        /// C value type: `struct ip_msfilter`
+        MsFilter = bindings::IP_MSFILTER,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Retrieve the MTU of the socket.
+        ///
+        /// C value type: `int`
+        Mtu = bindings::IP_MTU,
+        u32,
+        ReadableOption
+    );
+    impl_ip_opt!(
+        /// Discover the MTU of the path to a destination.
+        ///
+        /// C value type: `int`
+        MtuDiscover = bindings::IP_MTU_DISCOVER,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Modify delivery policy of messages.
+        ///
+        /// C value type: `int`
+        MulticastAll = bindings::IP_MULTICAST_ALL,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set the interface for outgoing multicast packets.
+        ///
+        /// C value type: `struct in_addr`
+        MulticastInterface = bindings::IP_MULTICAST_IF,
+        Ipv4Addr,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set whether multicast packets are looped back to the sender.
+        ///
+        /// C value type: `int`
+        MulticastLoop = bindings::IP_MULTICAST_LOOP,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set the TTL of outgoing multicast packets.
+        ///
+        /// C value type: `int`
+        MulticastTtl = bindings::IP_MULTICAST_TTL,
+        u8,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Whether to disable reassembling of fragmented packets.
+        ///
+        /// C value type: `int`
+        NoDefrag = bindings::IP_NODEFRAG,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set the options to be included in outgoing packets.
+        ///
+        /// C value type: `char *`
+        IpOptions = bindings::IP_OPTIONS,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Enable receiving security context with the packet.
+        ///
+        /// C value type: `int`
+        PassSec = bindings::IP_PASSSEC,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Enable extended reliable error message passing.
+        ///
+        /// C value type: `int`
+        RecvErr = bindings::IP_RECVERR,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Pass all IP Router Alert messages to this socket.
+        ///
+        /// C value type: `int`
+        RouterAlert = bindings::IP_ROUTER_ALERT,
+        bool,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set the TOS field of outgoing packets.
+        ///
+        /// C value type: `int`
+        Tos = bindings::IP_TOS,
+        u8,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set transparent proxying.
+        ///
+        /// C value type: `int`
+        Transparent = bindings::IP_TRANSPARENT,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Set the TTL of outgoing packets.
+        ///
+        /// C value type: `int`
+        Ttl = bindings::IP_TTL,
+        u8,
+        ReadableOption,
+        WritableOption
+    );
+    impl_ip_opt!(
+        /// Unblock packets from a specific source.
+        ///
+        /// C value type: `struct ip_mreq_source`
+        UnblockSource = bindings::IP_UNBLOCK_SOURCE,
+        unimplemented,
+        WritableOption
+    );
+}
+
+pub mod sock {
+    //! Socket options.
+    use super::*;
+    use crate::net::ip::IpProtocol;
+    use crate::net::socket::SockType;
+    use crate::net::AddressFamily;
+    macro_rules! impl_sock_opt {
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        unimplemented,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Socket,
+                unimplemented,
+                $($tr),*
+            );
+        };
+
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        $rtyp:ty,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Socket,
+                $rtyp,
+                $($tr),*
+            );
+        };
+    }
+
+    impl_sock_opt!(
+        /// Get whether the socket is accepting connections.
+        ///
+        /// C value type: `int`
+        AcceptConn = bindings::SO_ACCEPTCONN,
+        bool,
+        ReadableOption
+    );
+
+    impl_sock_opt!(
+        /// Attach a filter to the socket.
+        ///
+        /// C value type: `struct sock_fprog`
+        AttachFilter = bindings::SO_ATTACH_FILTER,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Attach a eBPF program to the socket.
+        ///
+        /// C value type: `struct sock_fprog`
+        AttachBpf = bindings::SO_ATTACH_BPF,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Bind the socket to a specific network device.
+        ///
+        /// C value type: `char *`
+        BindToDevice = bindings::SO_BINDTODEVICE,
+        &'static str,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Set the broadcast flag on the socket.
+        ///
+        /// Only valid for datagram sockets.
+        ///
+        /// C value type: `int`
+        Broadcast = bindings::SO_BROADCAST,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Enable BSD compatibility.
+        ///
+        /// C value type: `int`
+        BsdCompatible = bindings::SO_BSDCOMPAT,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Enable socket debugging.
+        ///
+        /// C value type: `int`
+        Debug = bindings::SO_DEBUG,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Remove BPF or eBPF program from the socket.
+        ///
+        /// The argument is ignored.
+        ///
+        /// C value type: `int`
+        DetachFilter = bindings::SO_DETACH_FILTER,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Get the domain of the socket.
+        ///
+        /// C value type: `int`
+        Domain = bindings::SO_DOMAIN,
+        AddressFamily,
+        ReadableOption
+    );
+    impl_sock_opt!(
+        /// Get and clear pending errors.
+        ///
+        /// C value type: `int`
+        Error = bindings::SO_ERROR,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Only send packets to directly connected peers.
+        ///
+        /// C value type: `int`
+        DontRoute = bindings::SO_DONTROUTE,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+    impl_sock_opt!(
+        /// Set or get the CPU affinity of a socket.
+        ///
+        /// C value type: `int`
+        IncomingCpu = bindings::SO_INCOMING_CPU,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Enable keep-alive packets.
+        ///
+        /// C value type: `int`
+        KeepAlive = bindings::SO_KEEPALIVE,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the linger timeout.
+        ///
+        /// C value type: `struct linger`
+        Linger = bindings::SO_LINGER,
+        Linger,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Prevent changing the filters attached to the socket.
+        ///
+        /// C value type: `int`
+        LockFilter = bindings::SO_LOCK_FILTER,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the mark of the socket.
+        ///
+        /// C value type: `int`
+        Mark = bindings::SO_MARK,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set whether out-of-band data is received in the normal data stream.
+        ///
+        /// C value type: `int`
+        OobInline = bindings::SO_OOBINLINE,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Enable the receiving of SCM credentials.
+        ///
+        /// C value type: `int`
+        PassCred = bindings::SO_PASSCRED,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set the peek offset for MSG_PEEK reads.
+        ///
+        /// Only valid for UNIX sockets.
+        ///
+        /// C value type: `int`
+        PeekOff = bindings::SO_PEEK_OFF,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the protocol-defined priority for all packets.
+        ///
+        /// C value type: `int`
+        Priority = bindings::SO_PRIORITY,
+        u8,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Retrieve the socket protocol
+        ///
+        /// C value type: `int`
+        Protocol = bindings::SO_PROTOCOL,
+        IpProtocol,
+        ReadableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the receive buffer size.
+        ///
+        /// C value type: `int`
+        RcvBuf = bindings::SO_RCVBUF,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the receive low watermark.
+        ///
+        /// C value type: `int`
+        RcvLowat = bindings::SO_RCVLOWAT,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the receive timeout.
+        ///
+        /// C value type: `struct timeval`
+        RcvTimeo = bindings::SO_RCVTIMEO_NEW,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the reuse address flag.
+        ///
+        /// C value type: `int`
+        ReuseAddr = bindings::SO_REUSEADDR,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the reuse port flag.
+        ///
+        /// C value type: `int`
+        ReusePort = bindings::SO_REUSEPORT,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the send buffer size.
+        ///
+        /// C value type: `int`
+        SndBuf = bindings::SO_SNDBUF,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the send timeout.
+        ///
+        /// C value type: `struct timeval`
+        SndTimeo = bindings::SO_SNDTIMEO_NEW,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set whether the timestamp control messages are received.
+        ///
+        /// C value type: `int`
+        Timestamp = bindings::SO_TIMESTAMP_NEW,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_sock_opt!(
+        /// Set or get the socket type.
+        ///
+        /// C value type: `int`
+        Type = bindings::SO_TYPE,
+        SockType,
+        ReadableOption
+    );
+}
+
+pub mod ipv6 {
+    //! IPv6 socket options.
+    use super::*;
+    use crate::net::AddressFamily;
+    macro_rules! impl_ipv6_opt {
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        unimplemented,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Ipv6,
+                unimplemented,
+                $($tr),*
+            );
+        };
+
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        $rtyp:ty,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Ipv6,
+                $rtyp,
+                $($tr),*
+            );
+        };
+    }
+
+    impl_ipv6_opt!(
+        /// Modify the address family used by the socket.
+        ///
+        /// C value type: `int`
+        AddrForm = bindings::IPV6_ADDRFORM,
+        AddressFamily,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Join a multicast group.
+        ///
+        /// C value type: `struct ipv6_mreq`
+        AddMembership = bindings::IPV6_ADD_MEMBERSHIP,
+        unimplemented,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Leave a multicast group.
+        ///
+        /// C value type: `struct ipv6_mreq`
+        DropMembership = bindings::IPV6_DROP_MEMBERSHIP,
+        unimplemented,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get the MTU of the socket.
+        ///
+        /// C value type: `int`
+        Mtu = bindings::IPV6_MTU,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or retrieve the MTU discovery settings.
+        ///
+        /// C value type: `int` (macros)
+        MtuDiscover = bindings::IPV6_MTU_DISCOVER,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get the multicast hop limit.
+        ///
+        /// Range is -1 to 255.
+        ///
+        /// C value type: `int`
+        MulticastHops = bindings::IPV6_MULTICAST_HOPS,
+        i16,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get the multicast interface.
+        ///
+        /// Only valid for datagram and raw sockets.
+        ///
+        /// C value type: `int`
+        MulticastInterface = bindings::IPV6_MULTICAST_IF,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or read whether multicast packets are looped back
+        ///
+        /// C value type: `int`
+        MulticastLoop = bindings::IPV6_MULTICAST_LOOP,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get whether IPV6_PKTINFO is enabled.
+        ///
+        /// Only valid for datagram and raw sockets.
+        ///
+        /// C value type: `int`
+        ReceivePktInfo = bindings::IPV6_PKTINFO,
+        bool,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get whether IPV6_RTHDR messages are delivered.
+        ///
+        /// Only valid for raw sockets.
+        ///
+        /// C value type: `int`
+        RouteHdr = bindings::IPV6_RTHDR,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get whether IPV6_DSTOPTS messages are delivered.
+        ///
+        /// Only valid for datagram and raw sockets.
+        ///
+        /// C value type: `int`
+        DestOptions = bindings::IPV6_DSTOPTS,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get whether IPV6_HOPOPTS messages are delivered.
+        ///
+        /// Only valid for datagram and raw sockets.
+        ///
+        /// C value type: `int`
+        HopOptions = bindings::IPV6_HOPOPTS,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get whether IPV6_FLOWINFO messages are delivered.
+        ///
+        /// Only valid for datagram and raw sockets.
+        ///
+        /// C value type: `int`
+        FlowInfo = bindings::IPV6_FLOWINFO,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Enable extended reliable error message reporting.
+        ///
+        /// C value type: `int`
+        RecvErr = bindings::IPV6_RECVERR,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Pass all Router Alert enabled messages to the socket.
+        ///
+        /// Only valid for raw sockets.
+        ///
+        /// C value type: `int`
+        RouterAlert = bindings::IPV6_ROUTER_ALERT,
+        bool,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set or get the unicast hop limit.
+        ///
+        /// Range is -1 to 255.
+        ///
+        /// C value type: `int`
+        UnicastHops = bindings::IPV6_UNICAST_HOPS,
+        i16,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_ipv6_opt!(
+        /// Set whether the socket can only send and receive IPv6 packets.
+        ///
+        /// C value type: `int`
+        V6Only = bindings::IPV6_V6ONLY,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+}
+
+pub mod raw {
+    //! Raw socket options.
+    //!
+    //! These options are only valid for sockets with type [`SockType::Raw`](kernel::net::socket::SockType::Raw).
+    macro_rules! impl_raw_opt {
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        unimplemented,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Raw,
+                unimplemented,
+                $($tr),*
+            );
+        };
+
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        $rtyp:ty,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Raw,
+                $rtyp,
+                $($tr),*
+            );
+        };
+    }
+
+    impl_raw_opt!(
+        /// Enable a filter for IPPROTO_ICMP raw sockets.
+        /// The filter has a bit set for each ICMP type to be filtered out.
+        ///
+        /// C value type: `struct icmp_filter`
+        Filter = bindings::ICMP_FILTER as isize,
+        unimplemented,
+        ReadableOption,
+        WritableOption
+    );
+}
+
+pub mod tcp {
+    //! TCP socket options.
+    //!
+    //! These options are only valid for sockets with type [`SockType::Stream`](kernel::net::socket::SockType::Stream)
+    //! and protocol [`IpProtocol::Tcp`](kernel::net::ip::IpProtocol::Tcp).
+    use super::*;
+    macro_rules! impl_tcp_opt {
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        unimplemented,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Tcp,
+                unimplemented,
+                $($tr),*
+            );
+        };
+
+        ($(#[$meta:meta])*
+        $opt:ident = $value:expr,
+        $rtyp:ty,
+        $($tr:ty),*) => {
+            impl_opt!(
+                $(#[$meta])*
+                $opt = $value,
+                OptionsLevel::Tcp,
+                $rtyp,
+                $($tr),*
+            );
+        };
+    }
+
+    impl_tcp_opt!(
+        /// Set or get the congestion control algorithm to be used.
+        ///
+        /// C value type: `char *`
+        Congestion = bindings::TCP_CONGESTION,
+        unimplemented, // &[u8]? what about lifetime?
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// If true, don't send partial frames.
+        ///
+        /// C value type: `int`
+        Cork = bindings::TCP_CORK,
+        bool,
+        WritableOption,
+        ReadableOption
+    );
+
+    impl_tcp_opt!(
+        /// Allow a listener to be awakened only when data arrives.
+        /// The value is the time to wait for data in milliseconds.
+        ///
+        /// C value type: `int`
+        DeferAccept = bindings::TCP_DEFER_ACCEPT,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Collect information about this socket.
+        ///
+        /// C value type: `struct tcp_info`
+        Info = bindings::TCP_INFO,
+        unimplemented,
+        ReadableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get maximum number of keepalive probes to send.
+        ///
+        /// C value type: `int`
+        KeepCount = bindings::TCP_KEEPCNT,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get the time in seconds to idle before sending keepalive probes.
+        ///
+        /// C value type: `int`
+        KeepIdle = bindings::TCP_KEEPIDLE,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get the time in seconds between keepalive probes.
+        ///
+        /// C value type: `int`
+        KeepInterval = bindings::TCP_KEEPINTVL,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get the lifetime or orphaned FIN_WAIT2 sockets.
+        ///
+        /// C value type: `int`
+        Linger2 = bindings::TCP_LINGER2,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get the maximum segment size for outgoing TCP packets.
+        ///
+        /// C value type: `int`
+        MaxSeg = bindings::TCP_MAXSEG,
+        i32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// If true, Nagle algorithm is disabled, i.e. segments are send as soon as possible.
+        ///
+        /// C value type: `int`
+        NoDelay = bindings::TCP_NODELAY,
+        bool,
+        WritableOption,
+        ReadableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get whether QuickAck mode is on.
+        /// If true, ACKs are sent immediately, rather than delayed.
+        ///
+        /// C value type: `int`
+        QuickAck = bindings::TCP_QUICKACK,
+        bool,
+        WritableOption,
+        ReadableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get the number of SYN retransmits before the connection is dropped.
+        ///
+        /// C value type: `int`
+        SynCount = bindings::TCP_SYNCNT,
+        u8,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get how long sent packets can remain unacknowledged before timing out.
+        /// The value is in milliseconds; 0 means to use the system default.
+        ///
+        /// C value type: `unsigned int`
+        UserTimeout = bindings::TCP_USER_TIMEOUT,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Set or get the maximum window size for TCP sockets.
+        ///
+        /// C value type: `int`
+        WindowClamp = bindings::TCP_WINDOW_CLAMP,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Enable Fast Open on the listener socket (RFC 7413).
+        /// The value is the maximum length of pending SYNs.
+        ///
+        /// C value type: `int`
+        FastOpen = bindings::TCP_FASTOPEN,
+        u32,
+        ReadableOption,
+        WritableOption
+    );
+
+    impl_tcp_opt!(
+        /// Enable Fast Open on the client socket (RFC 7413).
+        ///
+        /// C value type: `int`
+        FastOpenConnect = bindings::TCP_FASTOPEN_CONNECT,
+        bool,
+        ReadableOption,
+        WritableOption
+    );
+}
+
+/// Linger structure to set and get the [sock::Linger] option.
+/// This is a wrapper around the C struct `linger`.
+#[repr(transparent)]
+pub struct Linger(bindings::linger);
+
+impl Linger {
+    /// Create a "on" Linger object with the given linger time.
+    /// This is equivalent to `linger { l_onoff: 1, l_linger: linger_time }`.
+    /// The linger time is in seconds.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::opts::Linger;
+    /// let linger = Linger::on(10);
+    /// assert!(linger.is_on());
+    /// assert_eq!(linger.linger_time(), 10);
+    pub fn on(linger: i32) -> Self {
+        Linger(bindings::linger {
+            l_onoff: 1 as _,
+            l_linger: linger as _,
+        })
+    }
+
+    /// Create an "off" Linger object.
+    /// This is equivalent to `linger { l_onoff: 0, l_linger: 0 }`.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::opts::Linger;
+    /// let linger = Linger::off();
+    /// assert!(!linger.is_on());
+    pub fn off() -> Self {
+        Linger(bindings::linger {
+            l_onoff: 0 as _,
+            l_linger: 0 as _,
+        })
+    }
+
+    /// Get whether the linger option is on.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::opts::Linger;
+    /// let linger = Linger::on(10);
+    /// assert!(linger.is_on());
+    /// ```
+    ///
+    /// ```
+    /// use kernel::net::socket::opts::Linger;
+    /// let linger = Linger::off();
+    /// assert!(!linger.is_on());
+    /// ```
+    pub fn is_on(&self) -> bool {
+        self.0.l_onoff != 0
+    }
+
+    /// Get the linger time in seconds.
+    /// If the linger option is off, this will return 0.
+    ///
+    /// # Example
+    /// ```
+    /// use kernel::net::socket::opts::Linger;
+    /// let linger = Linger::on(10);
+    /// assert_eq!(linger.linger_time(), 10);
+    /// ```
+    pub fn linger_time(&self) -> i32 {
+        self.0.l_linger as _
+    }
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH 6/7] rust: net: add socket TCP wrappers.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
                   ` (4 preceding siblings ...)
  2023-08-14  9:23 ` [RFC PATCH 5/7] rust: net: implement socket options API Michele Dalle Rive
@ 2023-08-14  9:23 ` Michele Dalle Rive
  2023-08-14  9:23 ` [RFC PATCH 7/7] rust: net: add socket UDP wrappers Michele Dalle Rive
  2023-08-14 15:25 ` [RFC PATCH 0/7] Rust Socket abstractions Greg KH
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:23 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Add `TcpListener` and `TcpStream` wrappers around the Rust Socket.
They provide a convenient way to handle TCP sockets.

This interface is intended to be as close as possible to the one in `std::net`.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
 rust/kernel/net.rs     |   1 +
 rust/kernel/net/tcp.rs | 252 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 rust/kernel/net/tcp.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index 7d58ebb0324f..c7d9d4b0bcab 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -13,6 +13,7 @@
 pub mod addr;
 pub mod ip;
 pub mod socket;
+pub mod tcp;
 
 /// The address family.
 ///
diff --git a/rust/kernel/net/tcp.rs b/rust/kernel/net/tcp.rs
new file mode 100644
index 000000000000..86a42ac3e367
--- /dev/null
+++ b/rust/kernel/net/tcp.rs
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! TCP socket wrapper.
+//!
+//! This module contains wrappers for a TCP Socket ([`TcpListener`]) and an active
+//! TCP connection ([`TcpStream`]).
+//! The wrappers are just convenience structs around the generic [`Socket`] type.
+//!
+//! The API is inspired by the Rust standard library's [`TcpListener`](https://doc.rust-lang.org/std/net/struct.TcpListener.html) and [`TcpStream`](https://doc.rust-lang.org/std/net/struct.TcpStream.html).
+
+use crate::error::Result;
+use crate::net::addr::SocketAddr;
+use crate::net::ip::IpProtocol;
+use crate::net::socket::flags::{FlagSet, ReceiveFlag, SendFlag};
+use crate::net::socket::opts::{SocketOption, WritableOption};
+use crate::net::socket::{ShutdownCmd, SockType, Socket};
+use crate::net::AddressFamily;
+use kernel::net::socket::MessageHeader;
+
+/// A TCP listener.
+///
+/// Wraps the [`Socket`] type to create a TCP-specific interface.
+///
+/// The wrapper abstracts away the generic Socket methods that a connection-oriented
+/// protocol like TCP does not need.
+///
+/// # Examples
+/// ```rust
+/// use kernel::net::tcp::TcpListener;
+/// use kernel::net::addr::*;
+///
+/// let listener = TcpListener::new(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+/// while let Ok(stream) = listener.accept() {
+///   // ...
+/// }
+pub struct TcpListener(pub(crate) Socket);
+
+impl TcpListener {
+    /// Create a new TCP listener bound to the given address.
+    ///
+    /// The listener will be ready to accept connections.
+    pub fn new(address: SocketAddr) -> Result<Self> {
+        let socket = Socket::new(AddressFamily::Inet, SockType::Stream, IpProtocol::Tcp)?;
+        socket.bind(address)?;
+        socket.listen(128)?;
+        Ok(Self(socket))
+    }
+
+    /// Returns the local address that this listener is bound to.
+    ///
+    /// See [`Socket::sockname()`] for more.
+    pub fn sockname(&self) -> Result<SocketAddr> {
+        self.0.sockname()
+    }
+
+    /// Returns an iterator over incoming connections.
+    ///
+    /// Each iteration will return a [`Result`] containing a [`TcpStream`] on success.
+    /// See [`TcpIncoming`] for more.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::tcp::TcpListener;
+    /// use kernel::net::addr::*;
+    ///
+    /// let listener = TcpListener::new(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+    /// for stream in listener.incoming() {
+    ///    // ...
+    /// }
+    /// ```
+    pub fn incoming(&self) -> TcpIncoming<'_> {
+        TcpIncoming { listener: self }
+    }
+
+    /// Accepts an incoming connection.
+    ///
+    /// Returns a [`TcpStream`] on success.
+    pub fn accept(&self) -> Result<TcpStream> {
+        Ok(TcpStream(self.0.accept(true)?))
+    }
+
+    /// Sets the value of the given option.
+    ///
+    /// See [`Socket::set_option()`](Socket::set_option) for more.
+    pub fn set_option<O>(&self, value: impl Into<O::Type>) -> Result
+    where
+        O: SocketOption + WritableOption,
+    {
+        self.0.set_option::<O>(value)
+    }
+}
+
+/// An iterator over incoming connections from a [`TcpListener`].
+///
+/// Each iteration will return a [`Result`] containing a [`TcpStream`] on success.
+/// The iterator will never return [`None`].
+///
+/// This struct is created by the [`TcpListener::incoming()`] method.
+pub struct TcpIncoming<'a> {
+    listener: &'a TcpListener,
+}
+
+impl Iterator for TcpIncoming<'_> {
+    /// The item type of the iterator.
+    type Item = Result<TcpStream>;
+
+    /// Get the next connection from the listener.
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(self.listener.accept())
+    }
+}
+
+/// A TCP stream.
+///
+/// Represents an active TCP connection between two sockets.
+/// The stream can be opened by the listener, with [`TcpListener::accept()`], or by
+/// connecting to a remote address with [`TcpStream::connect()`].
+/// The stream can be used to send and receive data.
+///
+/// See [`TcpListener`] for an example of how to create a [`TcpStream`].
+pub struct TcpStream(pub(crate) Socket);
+
+impl TcpStream {
+    /// Opens a TCP stream by connecting to the given address.
+    ///
+    /// Returns a [`TcpStream`] on success.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::tcp::TcpStream;
+    /// use kernel::net::addr::*;
+    ///
+    /// let peer_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// let stream = TcpStream::connect(&peer_addr).unwrap();
+    /// ```
+    pub fn connect(address: &SocketAddr) -> Result<Self> {
+        let socket = Socket::new(AddressFamily::Inet, SockType::Stream, IpProtocol::Tcp)?;
+        socket.connect(address, 0)?;
+        Ok(Self(socket))
+    }
+
+    /// Returns the address of the remote peer of this connection.
+    ///
+    /// See [`Socket::peername()`] for more.
+    pub fn peername(&self) -> Result<SocketAddr> {
+        self.0.peername()
+    }
+
+    /// Returns the address of the local socket of this connection.
+    ///
+    /// See [`Socket::sockname()`] for more.
+    pub fn sockname(&self) -> Result<SocketAddr> {
+        self.0.sockname()
+    }
+
+    /// Receive data from the stream.
+    /// The given flags are used to modify the behavior of the receive operation.
+    /// See [`ReceiveFlag`] for more.
+    ///
+    /// Returns the number of bytes received.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::flag_set;
+    /// use kernel::net::tcp::TcpListener;
+    /// use kernel::net::addr::*;
+    ///
+    /// let listener = TcpListener::new(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+    /// while let Ok(stream) = listener.accept() {
+    ///     let mut buf = [0u8; 1024];
+    ///     while let Ok(len) = stream.receive(&mut buf, flag_set!()) {
+    ///         // ...
+    ///     }
+    /// }
+    /// ```
+    pub fn receive(&self, buf: &mut [u8], flags: FlagSet<ReceiveFlag>) -> Result<usize> {
+        self.0.receive(buf, flags)
+    }
+
+    /// Receive data from the stream and return the message header.
+    ///
+    /// The given flags are used to modify the behavior of the receive operation.
+    ///
+    /// Returns the number of bytes received and the message header, which contains
+    /// information about the sender and the message.
+    ///
+    /// See [`Socket::receive_msg()`] for more.
+    pub fn receive_msg(
+        &self,
+        buf: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, MessageHeader)> {
+        self.0.receive_msg(buf, flags)
+    }
+
+    /// Send data to the stream.
+    ///
+    /// The given flags are used to modify the behavior of the send operation.
+    /// See [`SendFlag`] for more.
+    ///
+    /// Returns the number of bytes sent.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::flag_set;
+    /// use kernel::net::tcp::TcpListener;
+    /// use kernel::net::addr::*;
+    ///
+    /// let listener = TcpListener::new(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+    /// while let Ok(stream) = listener.accept() {
+    ///     let mut buf = [0u8; 1024];
+    ///     while let Ok(len) = stream.receive(&mut buf, flag_set!()) {
+    ///         stream.send(&buf[..len], flag_set!())?;
+    ///     }
+    /// }
+    /// ```
+    pub fn send(&self, buf: &[u8], flags: FlagSet<SendFlag>) -> Result<usize> {
+        self.0.send(buf, flags)
+    }
+
+    /// Manually shutdown some portion of the stream.
+    /// See [`ShutdownCmd`] for more.
+    ///
+    /// This method is not required to be called, as the stream will be shutdown
+    /// automatically when it is dropped.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::tcp::TcpListener;
+    /// use kernel::net::addr::*;
+    /// use kernel::net::socket::ShutdownCmd;
+    ///
+    /// let listener = TcpListener::new(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+    /// while let Ok(stream) = listener.accept() {
+    ///    // ...
+    ///    stream.shutdown(ShutdownCmd::Both)?;
+    /// }
+    /// ```
+    pub fn shutdown(&self, how: ShutdownCmd) -> Result {
+        self.0.shutdown(how)
+    }
+}
+
+impl Drop for TcpStream {
+    /// Shutdown the stream.
+    ///
+    /// This method ignores the outcome of the shutdown operation: whether the stream
+    /// is successfully shutdown or not, the stream will be dropped anyways.
+    fn drop(&mut self) {
+        self.0.shutdown(ShutdownCmd::Both).ok();
+    }
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [RFC PATCH 7/7] rust: net: add socket UDP wrappers.
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
                   ` (5 preceding siblings ...)
  2023-08-14  9:23 ` [RFC PATCH 6/7] rust: net: add socket TCP wrappers Michele Dalle Rive
@ 2023-08-14  9:23 ` Michele Dalle Rive
  2023-08-14 15:25 ` [RFC PATCH 0/7] Rust Socket abstractions Greg KH
  7 siblings, 0 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14  9:23 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller
  Cc: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches,
	Michele Dalle Rive

Add a UDP socket wrapper, which allows to handle UDP sockets conveniently.

This interface is intended to be as close as possible to the one in `std::net`.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
 rust/kernel/net.rs     |   1 +
 rust/kernel/net/udp.rs | 182 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 183 insertions(+)
 create mode 100644 rust/kernel/net/udp.rs

diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
index c7d9d4b0bcab..c527bd1fb0a8 100644
--- a/rust/kernel/net.rs
+++ b/rust/kernel/net.rs
@@ -14,6 +14,7 @@
 pub mod ip;
 pub mod socket;
 pub mod tcp;
+pub mod udp;
 
 /// The address family.
 ///
diff --git a/rust/kernel/net/udp.rs b/rust/kernel/net/udp.rs
new file mode 100644
index 000000000000..9193292a30f6
--- /dev/null
+++ b/rust/kernel/net/udp.rs
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! UDP socket wrapper.
+//!
+//! This module contains wrappers for a UDP Socket ([`UdpSocket`]).
+//! The wrapper is just convenience structs around the generic [`Socket`] type.
+//!
+//! The API is inspired by the Rust standard library's [`UdpSocket`](https://doc.rust-lang.org/std/net/struct.UdpSocket.html).
+
+use crate::error::Result;
+use crate::net::addr::SocketAddr;
+use crate::net::ip::IpProtocol;
+use crate::net::socket::flags::{FlagSet, ReceiveFlag, SendFlag};
+use crate::net::socket::{opts::SocketOption, MessageHeader, SockType, Socket};
+use crate::net::AddressFamily;
+use kernel::net::socket::opts::WritableOption;
+
+/// A UDP socket.
+///
+/// Provides an interface to send and receive UDP packets, removing
+/// all the socket functionality that is not needed for UDP.
+///
+/// # Examples
+/// ```rust
+/// use kernel::flag_set;
+/// use kernel::net::udp::UdpSocket;
+/// use kernel::net::addr::*;
+///
+/// let socket = UdpSocket::new().unwrap();
+/// socket.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000))).unwrap();
+/// let mut buf = [0u8; 1024];
+/// while let Ok((len, addr)) = socket.receive_from(&mut buf, flag_set!()) {
+///     socket.send_to(&buf[..len], &addr, flag_set!()).unwrap();
+/// }
+/// ```
+pub struct UdpSocket(pub(crate) Socket);
+
+impl UdpSocket {
+    /// Creates a UDP socket.
+    ///
+    /// Returns a [`UdpSocket`] on success.
+    pub fn new() -> Result<Self> {
+        Ok(Self(Socket::new(
+            AddressFamily::Inet,
+            SockType::Datagram,
+            IpProtocol::Udp,
+        )?))
+    }
+
+    /// Binds the socket to the given address.
+    pub fn bind(&self, address: SocketAddr) -> Result {
+        self.0.bind(address)
+    }
+
+    /// Returns the socket's local address.
+    ///
+    /// This function assumes the socket is bound,
+    /// i.e. it must be called after [`bind()`](UdpSocket::bind).
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::udp::UdpSocket;
+    /// use kernel::net::addr::*;
+    ///
+    /// let socket = UdpSocket::new().unwrap();
+    /// let local_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// socket.bind(local_addr).unwrap();
+    /// assert_eq!(socket.sockname().unwrap(), local_addr);
+    pub fn sockname(&self) -> Result<SocketAddr> {
+        self.0.sockname()
+    }
+
+    /// Returns the socket's peer address.
+    ///
+    /// This function assumes the socket is connected,
+    /// i.e. it must be called after [`connect()`](UdpSocket::connect).
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::udp::UdpSocket;
+    /// use kernel::net::addr::*;
+    ///
+    /// let socket = UdpSocket::new().unwrap();
+    /// let peer_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// socket.connect(&peer_addr).unwrap();
+    /// assert_eq!(socket.peername().unwrap(), peer_addr);
+    pub fn peername(&self) -> Result<SocketAddr> {
+        self.0.peername()
+    }
+
+    /// Receive a message from the socket.
+    ///
+    /// The given flags are used to modify the behavior of the receive operation.
+    /// See [`ReceiveFlag`] for more.
+    ///
+    /// The returned [`MessageHeader`] contains metadata about the received message.
+    ///
+    /// See [`Socket::receive_msg()`] for more.
+    pub fn receive_msg(
+        &self,
+        buf: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, MessageHeader)> {
+        self.0.receive_msg(buf, flags)
+    }
+
+    /// Receives data from another socket.
+    ///
+    /// The given flags are used to modify the behavior of the receive operation.
+    /// See [`ReceiveFlag`] for more.
+    ///
+    /// Returns the number of bytes received and the address of the sender.
+    pub fn receive_from(
+        &self,
+        buf: &mut [u8],
+        flags: FlagSet<ReceiveFlag>,
+    ) -> Result<(usize, SocketAddr)> {
+        self.0
+            .receive_from(buf, flags)
+            .map(|(size, addr)| (size, addr.unwrap()))
+    }
+
+    /// Sends data to another socket.
+    ///
+    /// The given flags are used to modify the behavior of the send operation.
+    /// See [`SendFlag`] for more.
+    ///
+    /// Returns the number of bytes sent.
+    pub fn send_to(
+        &self,
+        buf: &[u8],
+        address: &SocketAddr,
+        flags: FlagSet<SendFlag>,
+    ) -> Result<usize> {
+        self.0.send_to(buf, address, flags)
+    }
+
+    /// Connects the socket to the given address.
+    ///
+    /// # Examples
+    /// ```rust
+    /// use kernel::net::udp::UdpSocket;
+    /// use kernel::net::addr::*;
+    ///
+    /// let socket = UdpSocket::new().unwrap();
+    /// let peer_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOOPBACK, 8000));
+    /// socket.connect(&peer_addr).unwrap();
+    /// ```
+    pub fn connect(&self, address: &SocketAddr) -> Result {
+        self.0.connect(address, 0)
+    }
+
+    /// Receives data from the connected socket.
+    ///
+    /// This function assumes the socket is connected,
+    /// i.e. it must be called after [`connect()`](UdpSocket::connect).
+    ///
+    /// Returns the number of bytes received.
+    pub fn receive(&self, buf: &mut [u8], flags: FlagSet<ReceiveFlag>) -> Result<usize> {
+        self.0.receive(buf, flags)
+    }
+
+    /// Sends data to the connected socket.
+    ///
+    /// This function assumes the socket is connected,
+    /// i.e. it must be called after [`connect()`](UdpSocket::connect).
+    ///
+    /// Returns the number of bytes sent.
+    pub fn send(&self, buf: &[u8], flags: FlagSet<SendFlag>) -> Result<usize> {
+        self.0.send(buf, flags)
+    }
+
+    /// Sets the value of the given option.
+    ///
+    /// See [`Socket::set_option()`](Socket::set_option) for more.
+    pub fn set_option<O>(&self, value: impl Into<O::Type>) -> Result
+    where
+        O: SocketOption + WritableOption,
+    {
+        self.0.set_option::<O>(value)
+    }
+}
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
                   ` (6 preceding siblings ...)
  2023-08-14  9:23 ` [RFC PATCH 7/7] rust: net: add socket UDP wrappers Michele Dalle Rive
@ 2023-08-14 15:25 ` Greg KH
  2023-08-14 20:23   ` Andrew Lunn
  7 siblings, 1 reply; 26+ messages in thread
From: Greg KH @ 2023-08-14 15:25 UTC (permalink / raw)
  To: Michele Dalle Rive
  Cc: Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

On Mon, Aug 14, 2023 at 11:22:55AM +0200, Michele Dalle Rive wrote:
> This patch series is intended to create Rust abstractions for Sockets
> and other fundamental network entities. 
> 
> Specifically, it was added:
> - Ip address and Socket address wrappers (for `in_addr`, `in6_addr`,
>   `sockaddr_in`, `sockaddr_in6`, `sockaddr_storage`).
> - Socket wrapper.
> - Socket flags and options enums.
> - TCP and UDP specific abstractions over the Rust Socket structure.
> 
> This series is a RFC because I would appreciate some feedback about:
> - The structure of the module: is the division of the files and modules
>   appropriate or should it be more or less fine-grained?
>   Also, should the `net` module export all the structures of its
>   submodules? I noticed that it is done in the standard library.
> - Whether the documentation is comprehensive enough.
> - A few other specific questions, written in the individual patches.
> 
> I would greatly appreciate any kind of feedback or opinion. 
> I am pretty new to the patch/mailing list world, so please point out any
> mistake I might make.

The best feedback is "who will use these new interfaces?"  Without that,
it's really hard to review a patchset as it's difficult to see how the
bindings will be used, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-14 15:25 ` [RFC PATCH 0/7] Rust Socket abstractions Greg KH
@ 2023-08-14 20:23   ` Andrew Lunn
  2023-08-14 21:06     ` Michele Dalle Rive
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Lunn @ 2023-08-14 20:23 UTC (permalink / raw)
  To: Greg KH
  Cc: Michele Dalle Rive, Miguel Ojeda, Alex Gaynor,
	Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

On Mon, Aug 14, 2023 at 05:25:49PM +0200, Greg KH wrote:
> On Mon, Aug 14, 2023 at 11:22:55AM +0200, Michele Dalle Rive wrote:
> > This patch series is intended to create Rust abstractions for Sockets
> > and other fundamental network entities. 
> > 
> > Specifically, it was added:
> > - Ip address and Socket address wrappers (for `in_addr`, `in6_addr`,
> >   `sockaddr_in`, `sockaddr_in6`, `sockaddr_storage`).
> > - Socket wrapper.
> > - Socket flags and options enums.
> > - TCP and UDP specific abstractions over the Rust Socket structure.
> > 
> > This series is a RFC because I would appreciate some feedback about:
> > - The structure of the module: is the division of the files and modules
> >   appropriate or should it be more or less fine-grained?
> >   Also, should the `net` module export all the structures of its
> >   submodules? I noticed that it is done in the standard library.
> > - Whether the documentation is comprehensive enough.
> > - A few other specific questions, written in the individual patches.
> > 
> > I would greatly appreciate any kind of feedback or opinion. 
> > I am pretty new to the patch/mailing list world, so please point out any
> > mistake I might make.
> 
> The best feedback is "who will use these new interfaces?"  Without that,
> it's really hard to review a patchset as it's difficult to see how the
> bindings will be used, right?

There is a long standing tradition in Linux, you don't get a new API
merged without a user.

There is not too much use of in kernel sockets. Network file systems
like NFS, and SMB are one. These need to be careful with memory usage,
you could be busy writing blocks out because the system is low on
memory and trying to free some up, and asking for more memory might
not work.  Sending kernel log messages to a server. But that needs
care because of the different contexts it can be used in. Without
knowing what it will be used for, it is hard for us the point the
special considerations which need to be made.

So please also let us see the code using this API.

	Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-14 20:23   ` Andrew Lunn
@ 2023-08-14 21:06     ` Michele Dalle Rive
  2023-08-14 21:36       ` Andrew Lunn
  0 siblings, 1 reply; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-14 21:06 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Greg KH, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

On Mon, 14 Aug 2023 at 22:23, Andrew Lunn <andrew@lunn.ch> wrote:
>
> On Mon, Aug 14, 2023 at 05:25:49PM +0200, Greg KH wrote:
> > On Mon, Aug 14, 2023 at 11:22:55AM +0200, Michele Dalle Rive wrote:
> > > This patch series is intended to create Rust abstractions for Sockets
> > > and other fundamental network entities.
> > >
> > > Specifically, it was added:
> > > - Ip address and Socket address wrappers (for `in_addr`, `in6_addr`,
> > >   `sockaddr_in`, `sockaddr_in6`, `sockaddr_storage`).
> > > - Socket wrapper.
> > > - Socket flags and options enums.
> > > - TCP and UDP specific abstractions over the Rust Socket structure.
> > >
> > > This series is a RFC because I would appreciate some feedback about:
> > > - The structure of the module: is the division of the files and modules
> > >   appropriate or should it be more or less fine-grained?
> > >   Also, should the `net` module export all the structures of its
> > >   submodules? I noticed that it is done in the standard library.
> > > - Whether the documentation is comprehensive enough.
> > > - A few other specific questions, written in the individual patches.
> > >
> > > I would greatly appreciate any kind of feedback or opinion.
> > > I am pretty new to the patch/mailing list world, so please point out any
> > > mistake I might make.
> >
> > The best feedback is "who will use these new interfaces?"  Without that,
> > it's really hard to review a patchset as it's difficult to see how the
> > bindings will be used, right?
>
> There is a long standing tradition in Linux, you don't get a new API
> merged without a user.

Sorry for not being clear on that.

These abstractions are meant to be used by modules: having them, modules
can start using the kernel network functionalities through a first, high level
interface.

Since there is currently no network support in Rust, this patch series
represents a first step to provide access to networking to modules.
Sockets are just the highest layer of the network stack: the goal would be
to port structures deeper in the network stack, to give modules more
access to the network api. However, you need to start somewhere.

>
> There is not too much use of in kernel sockets. Network file systems
> like NFS, and SMB are one. These need to be careful with memory usage,
> you could be busy writing blocks out because the system is low on
> memory and trying to free some up, and asking for more memory might
> not work.  Sending kernel log messages to a server. But that needs
> care because of the different contexts it can be used in. Without
> knowing what it will be used for, it is hard for us the point the
> special considerations which need to be made.
>
> So please also let us see the code using this API.
>
>         Andrew

The lack of these abstractions was noticed in the context of a research
of the usability of Rust for the development of consensus algorithms using UDP.
Any kind of kernel module requiring network support can take advantage
of these socket abstractions, from a tcp echo server to any kind of complex
networking kernel module.

I could add an example kernel module in `samples/rust` showing an example
of usage of these APIs.

Thank you for your time,

Michele

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-14 21:06     ` Michele Dalle Rive
@ 2023-08-14 21:36       ` Andrew Lunn
  2023-08-17 14:53         ` Michele Dalle Rive
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Lunn @ 2023-08-14 21:36 UTC (permalink / raw)
  To: Michele Dalle Rive
  Cc: Greg KH, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

> > There is a long standing tradition in Linux, you don't get a new API
> > merged without a user.
> 
> Sorry for not being clear on that.
> 
> These abstractions are meant to be used by modules: having them, modules
> can start using the kernel network functionalities through a first, high level
> interface.
> 
> Since there is currently no network support in Rust, this patch series
> represents a first step to provide access to networking to modules.
> Sockets are just the highest layer of the network stack: the goal would be
> to port structures deeper in the network stack, to give modules more
> access to the network api. However, you need to start somewhere.
> 
> >
> > There is not too much use of in kernel sockets. Network file systems
> > like NFS, and SMB are one. These need to be careful with memory usage,
> > you could be busy writing blocks out because the system is low on
> > memory and trying to free some up, and asking for more memory might
> > not work.  Sending kernel log messages to a server. But that needs
> > care because of the different contexts it can be used in. Without
> > knowing what it will be used for, it is hard for us the point the
> > special considerations which need to be made.
> >
> > So please also let us see the code using this API.
> >
> >         Andrew
> 
> The lack of these abstractions was noticed in the context of a research
> of the usability of Rust for the development of consensus algorithms using UDP.

O.K, so what are the use cases for consensus algorithms using UDP
within the kernel? Where is this code? Ideally you should post it for
merging alongside the rust API to sockets its needs. We can then
review both together, just as we would if somebody were submitting a
new API in C along with its user.

    Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-14 21:36       ` Andrew Lunn
@ 2023-08-17 14:53         ` Michele Dalle Rive
  2023-08-17 15:14           ` Andrew Lunn
                             ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Michele Dalle Rive @ 2023-08-17 14:53 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Greg KH, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

On Mon, 14 Aug 2023 at 23:36, Andrew Lunn <andrew@lunn.ch> wrote:
>
> > > There is a long standing tradition in Linux, you don't get a new API
> > > merged without a user.
> >
> > Sorry for not being clear on that.
> >
> > These abstractions are meant to be used by modules: having them, modules
> > can start using the kernel network functionalities through a first, high level
> > interface.
> >
> > Since there is currently no network support in Rust, this patch series
> > represents a first step to provide access to networking to modules.
> > Sockets are just the highest layer of the network stack: the goal would be
> > to port structures deeper in the network stack, to give modules more
> > access to the network api. However, you need to start somewhere.
> >
> > >
> > > There is not too much use of in kernel sockets. Network file systems
> > > like NFS, and SMB are one. These need to be careful with memory usage,
> > > you could be busy writing blocks out because the system is low on
> > > memory and trying to free some up, and asking for more memory might
> > > not work.  Sending kernel log messages to a server. But that needs
> > > care because of the different contexts it can be used in. Without
> > > knowing what it will be used for, it is hard for us the point the
> > > special considerations which need to be made.
> > >
> > > So please also let us see the code using this API.
> > >
> > >         Andrew
> >
> > The lack of these abstractions was noticed in the context of a research
> > of the usability of Rust for the development of consensus algorithms using UDP.
>
> O.K, so what are the use cases for consensus algorithms using UDP
> within the kernel? Where is this code? Ideally you should post it for
> merging alongside the rust API to sockets its needs. We can then
> review both together, just as we would if somebody were submitting a
> new API in C along with its user.
>
>     Andrew

Hello Andrew,
in the last few days, I had the opportunity to discuss with some people from
the RustForLinux community.

I apologize for not being clear: the goal of these APIs was to give some
network support to, in particular, out-of-tree modules; they were not meant to
be used by a specific module that was planned to get upstreamed as well.
The idea behind this patch is that, as of now, Rust is not a viable option for
any OOT module that requires even the highest-level network support.

I am wondering whether the `net` subsystem is interested in reviewing, giving
feedback and eventually accepting code that is currently OOT-only.

Also, it would be interesting if you could provide us any module or
functionality you are planning to get in-tree which might use this interface;
it could be useful in order to understand the applicability of these
abstractions and find a concrete in-kernel use-case.

I included in the email a couple of sample OOT modules that showcase the
functionalities of the socket API; they will be attached as an actual patch if
there will be a v2.

Thank you for your time,
Michele


From 4c966f6ff3acd3b7c27f7a558648722b227d45a7 Mon Sep 17 00:00:00 2001
From: Michele Dalle Rive <dallerivemichele@gmail.com>
Date: Thu, 17 Aug 2023 15:51:47 +0200
Subject: [PATCH] rust: net: add OOT sample modules.

Add two sample modules that showcase some functionalities of the Rust
socket API.

Signed-off-by: Michele Dalle Rive <dallerivemichele@gmail.com>
---
 samples/rust/rust_socket.rs     | 45 +++++++++++++++++++++++++++++++++
 samples/rust/rust_tcp_server.rs | 34 +++++++++++++++++++++++++
 2 files changed, 79 insertions(+)
 create mode 100644 samples/rust/rust_socket.rs
 create mode 100644 samples/rust/rust_tcp_server.rs

diff --git a/samples/rust/rust_socket.rs b/samples/rust/rust_socket.rs
new file mode 100644
index 000000000000..fc1ed8536e57
--- /dev/null
+++ b/samples/rust/rust_socket.rs
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust minimal sample.
+
+use core::str::FromStr;
+use kernel::prelude::*;
+use kernel::net::socket::*;
+use kernel::net::ip::IpProtocol;
+use kernel::net::addr::{SocketAddr};
+use kernel::net::AddressFamily;
+use kernel::flag_set;
+
+module! {
+    type: RustSocket,
+    name: "rust_socket",
+    author: "Rust for Linux Contributors",
+    description: "Rust sockets support sample",
+    license: "GPL",
+}
+
+struct RustSocket {}
+
+impl kernel::Module for RustSocket {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        let sock = Socket::new(AddressFamily::Inet,
SockType::Datagram, IpProtocol::Udp)?;
+        let addr = "0.0.0.0:8000";
+        sock.bind(SocketAddr::from_str(addr)?)?;
+
+        sock.set_option::<opts::sock::ReuseAddr>(true)?;
+
+        assert_eq!(sock.sockname()?, SocketAddr::from_str(addr)?);
+
+        let mut buf = [0; 1024];
+        while let Ok((bytes, msghdr)) = sock.receive_msg(&mut buf,
flag_set!()) {
+            if bytes == 0 {
+                break;
+            }
+            pr_info!("Received {} bytes from {}", bytes,
msghdr.address().unwrap());
+            if msghdr.flags().contains(flags::MessageFlag::Trunc) {
+                pr_info!("The message was truncated");
+            }
+        }
+        Ok(Self{})
+    }
+}
\ No newline at end of file
diff --git a/samples/rust/rust_tcp_server.rs b/samples/rust/rust_tcp_server.rs
new file mode 100644
index 000000000000..987c4c752d2b
--- /dev/null
+++ b/samples/rust/rust_tcp_server.rs
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust echo server sample.
+
+use core::str::FromStr;
+use kernel::prelude::*;
+use kernel::net::tcp::TcpListener;
+use kernel::net::addr::SocketAddr;
+use kernel::flag_set;
+
+module! {
+    type: RustTcpServer,
+    name: "rust_tcp_server",
+    author: "Rust for Linux Contributors",
+    license: "GPL",
+}
+
+struct RustTcpServer {}
+
+impl kernel::Module for RustTcpServer {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        let listener =
TcpListener::new(SocketAddr::from_str("0.0.0.0:8000")?)?;
+        while let Ok(stream) = listener.accept() {
+            let mut buf = [0; 1024];
+            while let Ok(size) = stream.receive(&mut buf, flag_set!()) {
+                if size == 0 {
+                    break;
+                }
+                stream.send(&buf[..size], flag_set!())?;
+            }
+        }
+        Ok(Self {})
+    }
+}
-- 
2.41.0

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 14:53         ` Michele Dalle Rive
@ 2023-08-17 15:14           ` Andrew Lunn
  2023-08-17 15:48           ` Jakub Kicinski
  2023-08-17 17:14           ` Miguel Ojeda
  2 siblings, 0 replies; 26+ messages in thread
From: Andrew Lunn @ 2023-08-17 15:14 UTC (permalink / raw)
  To: Michele Dalle Rive
  Cc: Greg KH, Miguel Ojeda, Alex Gaynor, Wedson Almeida Filho,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

> I am wondering whether the `net` subsystem is interested in reviewing, giving
> feedback and eventually accepting code that is currently OOT-only.

netdev, and the linux kernel in general, has no interest in code to
support out of tree modules. It adds maintenance cost for no gain.
 
> Also, it would be interesting if you could provide us any module or
> functionality you are planning to get in-tree which might use this interface;
> it could be useful in order to understand the applicability of these
> abstractions and find a concrete in-kernel use-case.

You need real code which does something useful for the community. Your
problem is, there is little use of sockets inside the kernel. I did
list a few examples in my first reply. Network file systems, logging
kernel messages to a remote server. I thought of one more afterwards,
there is dhcp client code used for NFS root, which could make use of
raw sockets.

However, you have the problem you cannot just rewrite this existing
code in Rust because it is core code and needs to work on all
architectures. And my understanding is, there are currently not Rust
compilers for all architectures.

What you can however do is implement something new, which the kernel
does not have. If it never existed, it is hard to complain it is only
available for a restricted number of architectures. So maybe look
through the RFCs and IETF documents and see if you can find something
which is both useful, and makes sense to be implemented in the kernel.

      Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 14:53         ` Michele Dalle Rive
  2023-08-17 15:14           ` Andrew Lunn
@ 2023-08-17 15:48           ` Jakub Kicinski
  2023-08-17 17:01             ` Boqun Feng
                               ` (2 more replies)
  2023-08-17 17:14           ` Miguel Ojeda
  2 siblings, 3 replies; 26+ messages in thread
From: Jakub Kicinski @ 2023-08-17 15:48 UTC (permalink / raw)
  To: Michele Dalle Rive
  Cc: Andrew Lunn, Greg KH, Miguel Ojeda, Alex Gaynor,
	Wedson Almeida Filho, David S. Miller, Eric Dumazet, Paolo Abeni,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

On Thu, 17 Aug 2023 16:53:03 +0200 Michele Dalle Rive wrote:
> in the last few days, I had the opportunity to discuss with some people from
> the RustForLinux community.
> 
> I apologize for not being clear: the goal of these APIs was to give some
> network support to, in particular, out-of-tree modules; they were not meant to
> be used by a specific module that was planned to get upstreamed as well.
> The idea behind this patch is that, as of now, Rust is not a viable option for
> any OOT module that requires even the highest-level network support.
> 
> I am wondering whether the `net` subsystem is interested in reviewing, giving
> feedback and eventually accepting code that is currently OOT-only.

This is a bit concerning. You can white out Rust in that and plonk in
some corporate backed project people tried to cram into the kernel
without understanding the community aspects. I'm not saying it's 
the same but the tone reads the same.

"The `net` subsystem" have given "the RustForLinux community" clear
guidance on what a good integration starting point is. And now someone
else from Rust comes in and talk about supporting OOT modules.

I thought the Rust was just shaking up the languages we use, not the
fundamentals on how this project operates :|

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 15:48           ` Jakub Kicinski
@ 2023-08-17 17:01             ` Boqun Feng
  2023-08-17 17:32             ` Miguel Ojeda
  2023-08-17 18:41             ` Jonathan Corbet
  2 siblings, 0 replies; 26+ messages in thread
From: Boqun Feng @ 2023-08-17 17:01 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Michele Dalle Rive, Andrew Lunn, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Paolo Abeni, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

On Thu, Aug 17, 2023 at 08:48:48AM -0700, Jakub Kicinski wrote:
> On Thu, 17 Aug 2023 16:53:03 +0200 Michele Dalle Rive wrote:
> > in the last few days, I had the opportunity to discuss with some people from
> > the RustForLinux community.
> > 
> > I apologize for not being clear: the goal of these APIs was to give some
> > network support to, in particular, out-of-tree modules; they were not meant to
> > be used by a specific module that was planned to get upstreamed as well.
> > The idea behind this patch is that, as of now, Rust is not a viable option for
> > any OOT module that requires even the highest-level network support.
> > 
> > I am wondering whether the `net` subsystem is interested in reviewing, giving
> > feedback and eventually accepting code that is currently OOT-only.
> 
> This is a bit concerning. You can white out Rust in that and plonk in
> some corporate backed project people tried to cram into the kernel
> without understanding the community aspects. I'm not saying it's 
> the same but the tone reads the same.
> 
> "The `net` subsystem" have given "the RustForLinux community" clear
> guidance on what a good integration starting point is. And now someone
> else from Rust comes in and talk about supporting OOT modules.
> 
> I thought the Rust was just shaking up the languages we use, not the
> fundamentals on how this project operates :|

I want to make it clear that Rust is not a way to get anyone a special
pass for OOT support. That's never the intention of people in RUST
maintainer entries.

Here Michele did a good job on honestly sharing the context of the work. 

After the patchset sent, there was a discusion in Rust-for-Linux zulip
about why a in-tree user is needed for review (and merge), and how
people who are interested in networking could work with netdev on
finding useful in-tree users and correct abstraction/bindings. I
personally didn't sense anyone trying to undermining the Linux kernel
development.

Please understand that "the RustForLinux community" cannot control
everyone's mind to make them aware of Linux kernel's contribution
policy, but surely there is no execuse not reading:

	https://docs.kernel.org/process/development-process.html	

before contribution.

Regards,
Boqun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 14:53         ` Michele Dalle Rive
  2023-08-17 15:14           ` Andrew Lunn
  2023-08-17 15:48           ` Jakub Kicinski
@ 2023-08-17 17:14           ` Miguel Ojeda
  2023-08-17 18:38             ` Stephen Hemminger
                               ` (2 more replies)
  2 siblings, 3 replies; 26+ messages in thread
From: Miguel Ojeda @ 2023-08-17 17:14 UTC (permalink / raw)
  To: Michele Dalle Rive
  Cc: Andrew Lunn, Greg KH, Miguel Ojeda, Alex Gaynor,
	Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

On Thu, Aug 17, 2023 at 4:53 PM Michele Dalle Rive
<dallerivemichele@gmail.com> wrote:
>
> The idea behind this patch is that, as of now, Rust is not a viable option for
> any OOT module that requires even the highest-level network support.
>
> I am wondering whether the `net` subsystem is interested in reviewing, giving
> feedback and eventually accepting code that is currently OOT-only.

It is unlikely kernel maintainers in general accept code intended for
out-of-tree modules only.

To be clear, Rust for Linux's focus has never been out-of-tree
modules. In fact, the whole effort since the beginning was about
adding support for Rust in-tree, unlike other projects that e.g.
linked `rustc`-built object files into an out-of-tree kernel module.

We do support out-of-tree modules, and have a sample of that, but that
is just only to the degree that the kernel supports out-of-tree
modules in general.

The abstractions that have been upstreamed so far are those that have
(or should soon have) a user in-tree. Sometimes we have had to bend a
bit the rules in order to split the dependency chain or make things
easier, but abstractions (in general) cannot be upstreamed that do not
have at least an expected and public user that is going upstream too.
Here, by user, we generally mean an actual driver or useful component
(rather than a sample).

If I understood correctly from Zulip, you cannot (right now) show your
use case because it is confidential and therefore you cannot upstream
it, so we will need another user (and, of course, that is a necessary
but not sufficient condition for the code to be accepted).

> Also, it would be interesting if you could provide us any module or
> functionality you are planning to get in-tree which might use this interface;
> it could be useful in order to understand the applicability of these
> abstractions and find a concrete in-kernel use-case.

I think it is easier if it is the other way around :) That is, the
people/companies that already have a use case for the abstractions
should come forward and publish them so that the abstractions are
justified.

Of course, this does not preclude discussing about them or having a
`rust-net` branch or sub-subsystem or similar. That could be quite
useful so develop those users and to experiment. In fact, we are
actively trying to onboard more people (and companies and other
entities) to the Rust overall kernel effort, so please feel free to
join us.

> I included in the email a couple of sample OOT modules that showcase the
> functionalities of the socket API; they will be attached as an actual patch if
> there will be a v2.

The sample should not be an out-of-tree module, it should be an
in-tree one. However, for upstreaming, just a sample is likely to not
be enough for most kernel maintainers, as mentioned above.

By the way, I am a bit confused -- the patch seems to add an in-tree
sample, not an out-of-tree one.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 15:48           ` Jakub Kicinski
  2023-08-17 17:01             ` Boqun Feng
@ 2023-08-17 17:32             ` Miguel Ojeda
  2023-08-17 18:41             ` Jonathan Corbet
  2 siblings, 0 replies; 26+ messages in thread
From: Miguel Ojeda @ 2023-08-17 17:32 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Michele Dalle Rive, Andrew Lunn, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Paolo Abeni, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Alice Ryhl, Davide Rovelli, rust-for-linux, netdev,
	linux-kernel, patches

On Thu, Aug 17, 2023 at 5:48 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> This is a bit concerning. You can white out Rust in that and plonk in
> some corporate backed project people tried to cram into the kernel
> without understanding the community aspects. I'm not saying it's
> the same but the tone reads the same.
>
> "The `net` subsystem" have given "the RustForLinux community" clear
> guidance on what a good integration starting point is. And now someone
> else from Rust comes in and talk about supporting OOT modules.
>
> I thought the Rust was just shaking up the languages we use, not the
> fundamentals on how this project operates :|

I am not sure what you mean by "from Rust", but to clarify, Rust for
Linux's focus has never been out-of-tree modules.

In fact, the whole effort since the beginning has been about adding
support for Rust in-tree, unlike other projects that e.g. linked
`rustc`-built object files into an out-of-tree kernel module. We have
also been advising interested parties/newcomers on kernel guidelines
etc.

And, of course, the Rust subsystem is definitely not trying to change
any fundamentals. If it looks like so, then please note that, like any
other subsystem, we may have patch submitters coming from different
backgrounds and not part of the Rust subsystem team.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 17:14           ` Miguel Ojeda
@ 2023-08-17 18:38             ` Stephen Hemminger
  2023-08-17 19:13               ` Miguel Ojeda
  2023-08-17 19:14             ` Andrew Lunn
  2023-08-17 22:27             ` Davide Rovelli
  2 siblings, 1 reply; 26+ messages in thread
From: Stephen Hemminger @ 2023-08-17 18:38 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Michele Dalle Rive, Andrew Lunn, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

On Thu, 17 Aug 2023 19:14:19 +0200
Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote:

> If I understood correctly from Zulip, you cannot (right now) show your
> use case because it is confidential and therefore you cannot upstream
> it, so we will need another user (and, of course, that is a necessary
> but not sufficient condition for the code to be accepted).

I thought Rust symbols were all export symbol GPL.
And therefore any Rust module using these must also be GPL.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 15:48           ` Jakub Kicinski
  2023-08-17 17:01             ` Boqun Feng
  2023-08-17 17:32             ` Miguel Ojeda
@ 2023-08-17 18:41             ` Jonathan Corbet
  2 siblings, 0 replies; 26+ messages in thread
From: Jonathan Corbet @ 2023-08-17 18:41 UTC (permalink / raw)
  To: Jakub Kicinski, Michele Dalle Rive
  Cc: Andrew Lunn, Greg KH, Miguel Ojeda, Alex Gaynor,
	Wedson Almeida Filho, David S. Miller, Eric Dumazet, Paolo Abeni,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Davide Rovelli, rust-for-linux, netdev, linux-kernel,
	patches

Jakub Kicinski <kuba@kernel.org> writes:

> I thought the Rust was just shaking up the languages we use, not the
> fundamentals on how this project operates :|

I don't think this little episode has anything to do with Rust, really;
certainly we've had no shortage of companies wanting support for
out-of-tree modules written in C over the years.

Instead, this is just the sort of thing you see when people who are new
to our community learn - the hard way, sometimes - how kernel
development works.  Rust seems likely to bring in a fair number of new
developers, which is great, but we're going to have to help them learn
their way around.

Thanks,

jon

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 18:38             ` Stephen Hemminger
@ 2023-08-17 19:13               ` Miguel Ojeda
  0 siblings, 0 replies; 26+ messages in thread
From: Miguel Ojeda @ 2023-08-17 19:13 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Michele Dalle Rive, Andrew Lunn, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

On Thu, Aug 17, 2023 at 8:38 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> I thought Rust symbols were all export symbol GPL.
> And therefore any Rust module using these must also be GPL.

They may be not distributing it just yet, e.g. it may be in
development as part of an academic paper, but they may be able to
publish later.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 17:14           ` Miguel Ojeda
  2023-08-17 18:38             ` Stephen Hemminger
@ 2023-08-17 19:14             ` Andrew Lunn
  2023-08-17 22:27             ` Davide Rovelli
  2 siblings, 0 replies; 26+ messages in thread
From: Andrew Lunn @ 2023-08-17 19:14 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Michele Dalle Rive, Greg KH, Miguel Ojeda, Alex Gaynor,
	Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

> If I understood correctly from Zulip, you cannot (right now) show your
> use case because it is confidential and therefore you cannot upstream
> it

Is there a clear path for it to become public and mergable?

There is also a general trend that code developed behind closed doors
needs a complete re-write when made public and reviewed by mainline
developers. And that rewrite could involve the APIs to other
subsystems, like sockets. So any API you define now with a 'toy' in
kernel user, could in fact be totally useless by the time your real
target gets merged.

As Jon pointed out, we kernel maintainers need to help people coming
from a different background. Within the community it is well known
that internal APIs are unstable. Any developer can change any API, and
all its in kernel users if there is a need to do so. This makes
maintaining out of tree modules hard. There are a number of 'vendor
crap' drivers which do do this, with lots of ugly code to work around
differences between kernel versions. To some extent, that works
because the C APIs are not that volatile. My guess is, the Rust APIs
are going to be a lot more volatile for a number of years while
developers figure out what good APIs look like, and rework them again
and again, and again. Anybody trying to maintain an out of tree rust
module is going to be in a world of pain. In tree however, benefits
from the fast that any developer who wants to change an API needs to
also change all users...

       Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 17:14           ` Miguel Ojeda
  2023-08-17 18:38             ` Stephen Hemminger
  2023-08-17 19:14             ` Andrew Lunn
@ 2023-08-17 22:27             ` Davide Rovelli
  2023-08-18  1:30               ` Andrew Lunn
  2 siblings, 1 reply; 26+ messages in thread
From: Davide Rovelli @ 2023-08-17 22:27 UTC (permalink / raw)
  To: Miguel Ojeda, Michele Dalle Rive
  Cc: Andrew Lunn, Greg KH, Miguel Ojeda, Alex Gaynor,
	Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches



On 8/17/23 19:14, Miguel Ojeda wrote:
> On Thu, Aug 17, 2023 at 4:53 PM Michele Dalle Rive
> <dallerivemichele@gmail.com> wrote:
>>
>> The idea behind this patch is that, as of now, Rust is not a viable option for
>> any OOT module that requires even the highest-level network support.
>>
>> I am wondering whether the `net` subsystem is interested in reviewing, giving
>> feedback and eventually accepting code that is currently OOT-only.
> 
> It is unlikely kernel maintainers in general accept code intended for
> out-of-tree modules only.
> 
> To be clear, Rust for Linux's focus has never been out-of-tree
> modules. In fact, the whole effort since the beginning was about
> adding support for Rust in-tree, unlike other projects that e.g.
> linked `rustc`-built object files into an out-of-tree kernel module.
> 
> We do support out-of-tree modules, and have a sample of that, but that
> is just only to the degree that the kernel supports out-of-tree
> modules in general.
> 
> The abstractions that have been upstreamed so far are those that have
> (or should soon have) a user in-tree. Sometimes we have had to bend a
> bit the rules in order to split the dependency chain or make things
> easier, but abstractions (in general) cannot be upstreamed that do not
> have at least an expected and public user that is going upstream too.
> Here, by user, we generally mean an actual driver or useful component
> (rather than a sample).
> 
> If I understood correctly from Zulip, you cannot (right now) show your
> use case because it is confidential and therefore you cannot upstream
> it, so we will need another user (and, of course, that is a necessary
> but not sufficient condition for the code to be accepted).

Correct. I work with Michele, let me clarify. We are a research lab 
working on a low-jitter networking prototype implemented as an internal 
LKM (our last paper: 
https://www.usenix.org/system/files/atc21-jahnke.pdf). When trying to 
convert it to Rust, we noticed the lack of socket abstractions which 
Michele implemented. We then simply thought about sharing the 
abstractions with the community since they could fit a variety of 
use-cases - hence the patch.
We now understand the necessity of a concrete in-tree user, apologies 
for not realising this earlier: we are indeed new to patch process as 
you probably understood.
Our prototype might become available in the future but there's no clear 
path on when, this is our starting point.

> Of course, this does not preclude discussing about them or having a
> `rust-net` branch or sub-subsystem or similar. That could be quite
> useful so develop those users and to experiment. In fact, we are
> actively trying to onboard more people (and companies and other
> entities) to the Rust overall kernel effort, so please feel free to
> join us.

We will be more than happy to. In fact, I think the best place for this 
patch would be in a net branch/subsystem of the Rust for Linux repo. As 
mentioned in the Zulip chat, it's hard to provide a "full-fledged" patch 
in Rust at this point as many network building blocks are missing. The 
result is a number of bindings patches such as this one which do not 
match maintainers' interests but could be useful for other developers to 
eventually make a concrete user. It would have helped us significantly 
when starting this project, I think other researchers/developers share 
the same view.
If anyone is interested, we could add these patches to the mailing list 
with a low priority tag for feedback.

> By the way, I am a bit confused -- the patch seems to add an in-tree
> sample, not an out-of-tree one.

It is an in-tree sample, I guess Michele meant an "out-of-tree use-case" 
as in the sample doesn't introduce new core features in the kernel, just 
showcasing.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-17 22:27             ` Davide Rovelli
@ 2023-08-18  1:30               ` Andrew Lunn
  2023-08-18  7:50                 ` Davide Rovelli
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Lunn @ 2023-08-18  1:30 UTC (permalink / raw)
  To: Davide Rovelli
  Cc: Miguel Ojeda, Michele Dalle Rive, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

> Correct. I work with Michele, let me clarify. We are a research lab working
> on a low-jitter networking prototype implemented as an internal LKM (our
> last paper: https://www.usenix.org/system/files/atc21-jahnke.pdf). When
> trying to convert it to Rust, we noticed the lack of socket abstractions
> which Michele implemented.

I guess i need to read the paper, or wait for the code to be made
public, but this API on its own does not make much sense to me. Or my
assumptions are all wrong.

So you have an application in user space wanting to use this
protocol. I assume it is using BSD sockets to communicate with the
kernel and the protocol. So you need an API below sockets to get this
traffic, i assume a whole new protocol family? But you have an API on
top of sockets for TCP/UDP. So i guess your protocol somehow
encapsulate the traffic and then uses the API your are proposing to
send over TCP or UDP?

Which makes me think:

Why go through sockets twice for a low jitter networking protocol?

How do you avoid deadlocks when you connect the bottom of sockets back
to the top of socket?

    Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-18  1:30               ` Andrew Lunn
@ 2023-08-18  7:50                 ` Davide Rovelli
  2023-08-18 12:42                   ` Andrew Lunn
  0 siblings, 1 reply; 26+ messages in thread
From: Davide Rovelli @ 2023-08-18  7:50 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Miguel Ojeda, Michele Dalle Rive, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches



On 8/18/23 03:30, Andrew Lunn wrote:

> So you have an application in user space wanting to use this
> protocol. I assume it is using BSD sockets to communicate with the
> kernel and the protocol. 

No, at the moment it uses procfs or a shared mmap'd chardev buffer.

> So you need an API below sockets to get this
> traffic, i assume a whole new protocol family? But you have an API on
> top of sockets for TCP/UDP. So i guess your protocol somehow
> encapsulate the traffic and then uses the API your are proposing to
> send over TCP or UDP?

Yes, we take a message/value from a user space app and send it to
other nodes via UDP according to the chosen protocol. Mind that
the term "protocol" might be misleading here as it can be confused
with classic network protocols. Our API offers distributed services
such as failure detectors, consensus etc.

> Which makes me think:
> 
> Why go through sockets twice for a low jitter networking protocol?

The idea behind the system is to be split: user space apps are
normal apps that can present arbitrary jitter, kernel space services
are isolated to provide low jitter. The same applies in the network
via a SDN based protocol which prioritises our traffic. By having
end-to-end timely communication and processing, we can achieve
new efficient distributed services.



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [RFC PATCH 0/7] Rust Socket abstractions
  2023-08-18  7:50                 ` Davide Rovelli
@ 2023-08-18 12:42                   ` Andrew Lunn
  0 siblings, 0 replies; 26+ messages in thread
From: Andrew Lunn @ 2023-08-18 12:42 UTC (permalink / raw)
  To: Davide Rovelli
  Cc: Miguel Ojeda, Michele Dalle Rive, Greg KH, Miguel Ojeda,
	Alex Gaynor, Wedson Almeida Filho, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Davide Rovelli,
	rust-for-linux, netdev, linux-kernel, patches

On Fri, Aug 18, 2023 at 09:50:45AM +0200, Davide Rovelli wrote:
> 
> 
> On 8/18/23 03:30, Andrew Lunn wrote:
> 
> > So you have an application in user space wanting to use this
> > protocol. I assume it is using BSD sockets to communicate with the
> > kernel and the protocol.
> 
> No, at the moment it uses procfs or a shared mmap'd chardev buffer.

O.K, so that will never be accepted. There is support for zero copy in
sockets. Look at the work Eric did. And you should look at netlink,
which might be needed for the control plane.
 
> > So you need an API below sockets to get this
> > traffic, i assume a whole new protocol family? But you have an API on
> > top of sockets for TCP/UDP. So i guess your protocol somehow
> > encapsulate the traffic and then uses the API your are proposing to
> > send over TCP or UDP?
> 
> Yes, we take a message/value from a user space app and send it to
> other nodes via UDP according to the chosen protocol. Mind that
> the term "protocol" might be misleading here as it can be confused
> with classic network protocols. Our API offers distributed services
> such as failure detectors, consensus etc.
> 
> > Which makes me think:
> > 
> > Why go through sockets twice for a low jitter networking protocol?
> 
> The idea behind the system is to be split: user space apps are
> normal apps that can present arbitrary jitter, kernel space services
> are isolated to provide low jitter. The same applies in the network
> via a SDN based protocol which prioritises our traffic. By having
> end-to-end timely communication and processing, we can achieve
> new efficient distributed services.

Having the services running in kernel space is going to limit what
services you can actually offer, if you need to go through getting
them merged every time. If you only have one or two, yes it can be
done. But anything general purpose is not going to be practical.  The
answer might be to write your services using eBPF. They can then be
loaded from user space and do pretty much anything which eBPF can do.

There is often a huge step from academic code to production
code. Academic code just needs to implement enough to prove the
concept. It can take all sort of short cuts. Production code to be
merged into the kernel needs to follow the usual development
processes, code quality guidelines, and most importantly,
architecture.

If you want to make that step to production code, we can help you, but
i don't think it makes any sense to merge API code until you have the
correct basic architecture. That architecture will define what APIs
you need, and sitting on top of sockets might not be correct.

	Andrew

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2023-08-18 12:42 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-14  9:22 [RFC PATCH 0/7] Rust Socket abstractions Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 1/7] rust: net: add net module files and shared enums Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 2/7] rust: net: add ip and socket address bindings Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 3/7] rust: net: add socket-related flags and flagset Michele Dalle Rive
2023-08-14  9:22 ` [RFC PATCH 4/7] rust: net: add socket wrapper Michele Dalle Rive
2023-08-14  9:23 ` [RFC PATCH 5/7] rust: net: implement socket options API Michele Dalle Rive
2023-08-14  9:23 ` [RFC PATCH 6/7] rust: net: add socket TCP wrappers Michele Dalle Rive
2023-08-14  9:23 ` [RFC PATCH 7/7] rust: net: add socket UDP wrappers Michele Dalle Rive
2023-08-14 15:25 ` [RFC PATCH 0/7] Rust Socket abstractions Greg KH
2023-08-14 20:23   ` Andrew Lunn
2023-08-14 21:06     ` Michele Dalle Rive
2023-08-14 21:36       ` Andrew Lunn
2023-08-17 14:53         ` Michele Dalle Rive
2023-08-17 15:14           ` Andrew Lunn
2023-08-17 15:48           ` Jakub Kicinski
2023-08-17 17:01             ` Boqun Feng
2023-08-17 17:32             ` Miguel Ojeda
2023-08-17 18:41             ` Jonathan Corbet
2023-08-17 17:14           ` Miguel Ojeda
2023-08-17 18:38             ` Stephen Hemminger
2023-08-17 19:13               ` Miguel Ojeda
2023-08-17 19:14             ` Andrew Lunn
2023-08-17 22:27             ` Davide Rovelli
2023-08-18  1:30               ` Andrew Lunn
2023-08-18  7:50                 ` Davide Rovelli
2023-08-18 12:42                   ` Andrew Lunn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.