xdp_socket/
peek.rs

1//! # Peeking at Descriptors in XDP Rings
2//!
3//! ## Purpose
4//!
5//! This file provides the logic for "peeking" at descriptors in an XDP ring.
6//! Peeking allows the application to get a reference to the data buffer (UMEM
7//! frame) associated with a descriptor without advancing the ring's consumer or
8//! producer indices. This is useful for inspecting or modifying data before
9//! committing to sending it (for TX) or after receiving it but before releasing
10//! the descriptor (for RX).
11//!
12//! ## How it works
13//!
14//! It implements methods on `Socket<_TX>` and `Socket<_RX>` that allow access
15//! to the underlying UMEM data buffers.
16//!
17//! For `_TX`, the methods return a mutable slice (`&mut [u8]`) to a UMEM frame,
18//! allowing the application to write packet data into the buffer before it is
19//! sent. The `len` of the data to be sent must be specified.
20//!
21//! For `_RX`, the methods return a slice (`&[u8]`) to a UMEM frame containing
22//! a received packet, allowing the application to read the data.
23//!
24//! ## Main components
25//!
26//! - `impl Socket<_TX>`: Provides `peek`, `peek_at`, and `seek_and_peek` for
27//!   transmit sockets.
28//! - `impl Socket<_RX>`: Provides `peek`, `peek_at`, and `seek_and_peek` for
29//!   receive sockets.
30
31#![allow(private_interfaces)]
32#![allow(private_bounds)]
33
34use crate::socket::{Socket, _TX, _RX, Seek_, RingError};
35
36impl Socket<_TX> where Socket<_TX>: Seek_<_TX> {
37    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
38    ///
39    /// This function finds the `index`-th descriptor in the range of AVAILABLE descriptors
40    /// and returns a mutable slice into the UMEM for writing (TX).
41    ///
42    /// # Arguments
43    ///
44    /// * `index` - The index in the range of available descriptors.
45    /// * `len` - The desired length of the chunk.
46    ///
47    /// # Returns
48    ///
49    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
50    fn peek_(&mut self, index: usize, len: usize) -> Result<&mut [u8], RingError> {
51        #[cfg(not(feature="no_safety_checks"))]
52        if index >= self.available as usize {
53            return Err(RingError::InvalidIndex);
54        }
55        #[cfg(not(feature="no_safety_checks"))]
56        if len > self.x_ring.frame_size() as usize {
57            return Err(RingError::InvalidLength);
58        }
59        let x_head = self.producer.wrapping_add(index as u32) & self.x_ring.mod_mask;
60        self.x_ring.mut_desc_at(x_head).len = len as u32;
61        Ok(self.x_ring.mut_bytes_at(self.frames, x_head, len))
62    }
63
64    /// Peeks at the next available chunk in the ring without advancing the head.
65    ///
66    /// This function finds the next available descriptor using `seek` and returns a
67    /// mutable slice into the UMEM for writing (TX) or reading (RX).
68    ///
69    /// # Arguments
70    ///
71    /// * `len` - The desired length of the chunk.
72    ///
73    /// # Returns
74    ///
75    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
76    #[inline]
77    pub fn peek(&mut self, len: usize) -> Result<&mut [u8], RingError> {
78        self.peek_(0, len)
79    }
80
81    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
82    ///
83    /// This function finds the `index`-th descriptor in the range of available descriptors
84    /// and returns a mutable slice into the UMEM for writing (TX).
85    ///
86    /// # Arguments
87    ///
88    /// * `index` - The index in the range of available descriptors.
89    /// * `len` - The desired length of the chunk.
90    ///
91    /// # Returns
92    ///
93    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
94    #[inline]
95    pub fn peek_at(&mut self, index: usize, len: usize) -> Result<&mut [u8], RingError> {
96        self.peek_(index, len)
97    }
98
99    /// Seeks to the next available descriptor in the ring and peeks at the descriptor
100    /// without advancing the head.
101    ///
102    /// This function calls `seek_` with a count of 1, and then calls `peek_` with a length
103    /// of `len`. It returns a mutable slice into the UMEM for writing (TX).
104    ///
105    /// # Arguments
106    ///
107    /// * `len` - The desired length of the chunk.
108    ///
109    /// # Returns
110    ///
111    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
112    pub fn seek_and_peek(&mut self, len: usize) -> Result<&mut [u8], RingError> {
113        self.seek_(1)?;
114        self.peek_(0, len)
115    }
116}
117
118impl Socket<_RX> where Socket<_RX>: Seek_<_RX> {
119    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
120    ///
121    /// This function finds the `index`-th descriptor in the range of available descriptors
122    /// and returns a byte slice into the UMEM for reading (RX).
123    ///
124    /// # Arguments
125    ///
126    /// * `index` - The index in the range of available descriptors.
127    ///
128    /// # Returns
129    ///
130    /// A `Result` containing a byte slice and its corresponding descriptor index.
131    fn peek_(&mut self, index: usize) -> Result<&[u8], RingError> {
132        #[cfg(not(feature="no_safety_checks"))]
133        if index >= self.available as usize {
134            return Err(RingError::InvalidIndex);
135        }
136        let x_head = self.consumer.wrapping_add(index as u32) & self.x_ring.mod_mask;
137        let len = self.x_ring.desc_at(x_head).len as usize;
138        Ok(self.x_ring.mut_bytes_at(self.frames, x_head, len))
139    }
140    /// Peeks at the first available chunk in the ring without advancing the head.
141    ///
142    /// This function finds the first descriptor in the range of available descriptors
143    /// and returns a byte slice into the UMEM for reading (RX).
144    ///
145    /// # Returns
146    ///
147    /// A `Result` containing a byte slice and its corresponding descriptor index.
148    #[inline]
149    pub fn peek(&mut self) -> Result<&[u8], RingError> {
150        self.peek_(0)
151    }
152
153    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
154    ///
155    /// This function finds the `index`-th descriptor in the range of available descriptors
156    /// and returns a byte slice into the UMEM for reading (RX).
157    ///
158    /// # Arguments
159    ///
160    /// * `index` - The index in the range of available descriptors.
161    ///
162    /// # Returns
163    ///
164    /// A `Result` containing a byte slice and its corresponding descriptor index.
165    #[inline]
166    pub fn peek_at(&mut self, index:usize) -> Result<&[u8], RingError> {
167        self.peek_(index)
168    }
169
170    /// Seeks to the next available descriptor in the ring and peeks at the descriptor
171    /// without advancing the head.
172    ///
173    /// This function calls `seek_` with a count of 1, and then calls `peek_` with a length
174    /// of the descriptor length. It returns a byte slice into the UMEM for reading (RX).
175    ///
176    /// # Returns
177    ///
178    /// A `Result` containing a byte slice and its corresponding descriptor index.
179    pub fn seek_and_peek(&mut self) -> Result<&[u8], RingError> {
180        self.seek_(1)?;
181        self.peek_(0)
182    }
183}