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}