xdp_socket/
send.rs

1//! # High-Level Packet Sending Logic
2//!
3//! ## Purpose
4//!
5//! This file provides the high-level `send` methods for the `TxSocket`. It offers a
6//! convenient API for users to send packet data without managing the underlying
7//! descriptors and rings directly.
8//!
9//! Since send and send_blocking is not a part of core API,
10//!   you have to import Send trait to enable it.
11//!
12//! ## How it works
13//!
14//! The user must first call `seek` or `seek_n` to ensure one or more UMEM frames
15//! are available for writing. The `send` method then takes the user's packet data,
16//! copies it into the next available frame, and calls `commit` to submit the
17//! descriptor to the kernel for transmission. It also provides a `send_blocking`
18//! variant that waits for the send to complete.
19//!
20//! ## Main components
21//!
22//! - `impl Socket<_TX>`: An implementation block for the transmit socket.
23//! - `send()`: A non-blocking method to send a slice of data.
24//! - `send_blocking()`: A blocking method that sends data and waits for the operation
25//!   to be acknowledged by the kernel.
26
27use crate::poll::PollWaitExt;
28use crate::socket::{_TX, Commit_, RingError, Seek_, Socket};
29
30/// A trait for high-level packet sending operations on XDP transmit sockets.
31///
32/// This trait provides methods to send packet data using an AF_XDP socket. It abstracts
33/// away the details of descriptor management and UMEM frame handling, offering a simple
34/// interface for non-blocking and blocking sends.
35///
36/// - `send`: Sends a packet in a non-blocking manner. You must ensure a frame is available
37///   by calling `seek` or `seek_n` before use.
38/// - `send_blocking`: Sends a packet and blocks until the kernel has processed the send.
39///
40/// # Arguments
41///
42/// * `data` - A byte slice containing the packet payload.
43/// * `header` - An optional byte slice for the packet header.
44///
45/// # Errors
46///
47/// Returns a `RingError` if the send fails or if no frame is available.
48///
49/// # Example
50///
51/// ```rust
52/// use xdp_socket::{create_tx_socket, SendExt as _ };
53/// let mut tx = create_tx_socket(...)?;
54/// tx.send(b"hello", None)?;
55/// ```
56pub trait SendExt {
57    fn send(&mut self, data: &[u8], header: Option<&[u8]>) -> Result<(), RingError>;
58    fn send_blocking(&mut self, data: &[u8], header: Option<&[u8]>) -> Result<(), RingError>;
59}
60
61/// An implementation block for the transmit socket (`TxSocket`) that provides
62/// high-level sending methods.
63impl SendExt for Socket<_TX>
64where
65    Socket<_TX>: Seek_<_TX> + Commit_<_TX> + PollWaitExt<_TX>,
66{
67    /// Sends a packet in a non-blocking manner.
68    ///
69    /// This method copies the provided data into a UMEM frame that has been
70    /// previously acquired via a call to `seek` or `seek_n`, and then submits it
71    /// to the kernel for transmission.
72    ///
73    /// Before calling this function, you must ensure that a frame is available by
74    /// calling `seek` or `seek_n`.
75    ///
76    /// # Arguments
77    /// * `data` - A byte slice containing the packet payload.
78    /// * `header` - An optional byte slice for the packet header. If provided, it is
79    ///   prepended to the data.
80    ///
81    /// # Returns
82    /// A `Result` indicating success or a `RingError` on failure.
83    ///
84    /// # Errors
85    ///
86    /// Returns `RingError::InvalidLength` if `data.len() + header.len()` exceeds
87    /// the UMEM frame size. Returns `RingError::InvalidIndex` if `seek` has not
88    /// been called to make a frame available.
89    fn send(&mut self, data: &[u8], header: Option<&[u8]>) -> Result<(), RingError> {
90        let hdr_len = header.map_or(0, |h| h.len());
91        let buf_len = data.len() + hdr_len;
92        let buf = self.peek(buf_len)?;
93        if let Some(bs) = header {
94            buf[0..hdr_len].copy_from_slice(bs);
95        }
96        buf[hdr_len..].copy_from_slice(data);
97        self.commit()
98    }
99
100    /// Sends a packet and blocks until the kernel has processed the send.
101    ///
102    /// This method first calls `send` to queue the packet and then blocks, waiting
103    /// for a kernel notification that the send is complete.
104    ///
105    /// Before calling this function, you must ensure that a frame is available by
106    /// calling `seek` or `seek_n`.
107    ///
108    /// # Arguments
109    /// * `data` - A byte slice containing the packet payload.
110    /// * `header` - An optional byte slice for the packet header.
111    ///
112    /// # Returns
113    /// A `Result` indicating success or a `RingError` on failure.
114    ///
115    /// # Errors
116    ///
117    /// In addition to the errors from `send`, this function can return
118    /// `RingError::Io` if the underlying `poll_wait` fails.
119    fn send_blocking(&mut self, data: &[u8], header: Option<&[u8]>) -> Result<(), RingError> {
120        self.send(data, header)?;
121        self.poll_wait(None).map_err(RingError::Io)?;
122        Ok(())
123    }
124}