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//! ## How it works
10//!
11//! The user must first call `seek` or `seek_n` to ensure one or more UMEM frames
12//! are available for writing. The `send` method then takes the user's packet data,
13//! copies it into the next available frame, and calls `commit` to submit the
14//! descriptor to the kernel for transmission. It also provides a `send_blocking`
15//! variant that waits for the send to complete.
16//!
17//! ## Main components
18//!
19//! - `impl Socket<_TX>`: An implementation block for the transmit socket.
20//! - `send()`: A non-blocking method to send a slice of data.
21//! - `send_blocking()`: A blocking method that sends data and waits for the operation
22//!   to be acknowledged by the kernel.
23
24use crate::socket::{RingError,_TX,Socket};
25
26/// An implementation block for the transmit socket (`TxSocket`) that provides
27/// high-level sending methods.
28impl Socket<_TX> {
29    /// Sends a packet in a non-blocking manner.
30    ///
31    /// This method copies the provided data into a UMEM frame that has been
32    /// previously acquired via a call to `seek` or `seek_n`, and then submits it
33    /// to the kernel for transmission.
34    ///
35    /// Before calling this function, you must ensure that a frame is available by
36    /// calling `seek` or `seek_n`.
37    ///
38    /// # Arguments
39    /// * `data` - A byte slice containing the packet payload.
40    /// * `header` - An optional byte slice for the packet header. If provided, it is
41    ///   prepended to the data.
42    ///
43    /// # Returns
44    /// A `Result` indicating success or a `RingError` on failure.
45    ///
46    /// # Errors
47    ///
48    /// Returns `RingError::InvalidLength` if `data.len() + header.len()` exceeds
49    /// the UMEM frame size. Returns `RingError::InvalidIndex` if `seek` has not
50    /// been called to make a frame available.
51    pub fn send(&mut self, data: &[u8], header: Option<&[u8]>) -> Result<(), RingError> {
52        let hdr_len = header.map_or(0, |h| h.len());
53        let buf_len = data.len() + hdr_len;
54        let buf = self.peek(buf_len)?;
55        if let Some(bs) = header {
56            buf[0..hdr_len].copy_from_slice(bs);
57        }
58        buf[hdr_len..].copy_from_slice(data);
59        self.commit()
60    }
61
62    /// Sends a packet and blocks until the kernel has processed the send.
63    ///
64    /// This method first calls `send` to queue the packet and then blocks, waiting
65    /// for a kernel notification that the send is complete.
66    ///
67    /// Before calling this function, you must ensure that a frame is available by
68    /// calling `seek` or `seek_n`.
69    ///
70    /// # Arguments
71    /// * `data` - A byte slice containing the packet payload.
72    /// * `header` - An optional byte slice for the packet header.
73    ///
74    /// # Returns
75    /// A `Result` indicating success or a `RingError` on failure.
76    ///
77    /// # Errors
78    ///
79    /// In addition to the errors from `send`, this function can return
80    /// `RingError::Io` if the underlying `poll_wait` fails.
81    pub fn send_blocking(&mut self, data: &[u8], header: Option<&[u8]>) -> Result<(), RingError> {
82        self.send(data, header)?;
83        self.poll_wait(None).map_err(RingError::Io)?;
84        Ok(())
85    }
86}