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}