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::{_RX, _TX, RingError, Seek_, Socket};
35
36impl Socket<_TX>
37where
38    Socket<_TX>: Seek_<_TX>,
39{
40    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
41    ///
42    /// This function finds the `index`-th descriptor in the range of AVAILABLE descriptors
43    /// and returns a mutable slice into the UMEM for writing (TX).
44    ///
45    /// # Arguments
46    ///
47    /// * `index` - The index in the range of available descriptors.
48    /// * `len` - The desired length of the chunk.
49    ///
50    /// # Returns
51    ///
52    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
53    fn peek_(&mut self, index: usize, len: usize) -> Result<&mut [u8], RingError> {
54        #[cfg(not(feature = "no_safety_checks"))]
55        if index >= self.available as usize {
56            return Err(RingError::InvalidIndex);
57        }
58        #[cfg(not(feature = "no_safety_checks"))]
59        if len > self.x_ring.frame_size() as usize {
60            return Err(RingError::InvalidLength);
61        }
62        let x_head = self.producer.wrapping_add(index as u32) & self.x_ring.mod_mask;
63        self.x_ring.mut_desc_at(x_head).len = len as u32;
64        Ok(self.x_ring.mut_bytes_at(self.frames, x_head, len))
65    }
66
67    /// Peeks at the next available chunk in the ring without advancing the head.
68    ///
69    /// This function finds the next available descriptor using `seek` and returns a
70    /// mutable slice into the UMEM for writing (TX) or reading (RX).
71    ///
72    /// # Arguments
73    ///
74    /// * `len` - The desired length of the chunk.
75    ///
76    /// # Returns
77    ///
78    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
79    #[inline]
80    pub fn peek(&mut self, len: usize) -> Result<&mut [u8], RingError> {
81        self.peek_(0, len)
82    }
83
84    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
85    ///
86    /// This function finds the `index`-th descriptor in the range of available descriptors
87    /// and returns a mutable slice into the UMEM for writing (TX).
88    ///
89    /// # Arguments
90    ///
91    /// * `index` - The index in the range of available descriptors.
92    /// * `len` - The desired length of the chunk.
93    ///
94    /// # Returns
95    ///
96    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
97    #[inline]
98    pub fn peek_at(&mut self, index: usize, len: usize) -> Result<&mut [u8], RingError> {
99        self.peek_(index, len)
100    }
101
102    /// Seeks to the next available descriptor in the ring and peeks at the descriptor
103    /// without advancing the head.
104    ///
105    /// This function calls `seek_` with a count of 1, and then calls `peek_` with a length
106    /// of `len`. It returns a mutable slice into the UMEM for writing (TX).
107    ///
108    /// # Arguments
109    ///
110    /// * `len` - The desired length of the chunk.
111    ///
112    /// # Returns
113    ///
114    /// A `Result` containing a mutable byte slice and its corresponding descriptor index.
115    pub fn seek_and_peek(&mut self, len: usize) -> Result<&mut [u8], RingError> {
116        self.seek_(1)?;
117        self.peek_(0, len)
118    }
119}
120
121impl Socket<_RX>
122where
123    Socket<_RX>: Seek_<_RX>,
124{
125    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
126    ///
127    /// This function finds the `index`-th descriptor in the range of available descriptors
128    /// and returns a byte slice into the UMEM for reading (RX).
129    ///
130    /// # Arguments
131    ///
132    /// * `index` - The index in the range of available descriptors.
133    ///
134    /// # Returns
135    ///
136    /// A `Result` containing a byte slice and its corresponding descriptor index.
137    fn peek_(&mut self, index: usize) -> Result<&[u8], RingError> {
138        #[cfg(not(feature = "no_safety_checks"))]
139        if index >= self.available as usize {
140            return Err(RingError::InvalidIndex);
141        }
142        let x_head = self.consumer.wrapping_add(index as u32) & self.x_ring.mod_mask;
143        let len = self.x_ring.desc_at(x_head).len as usize;
144        Ok(self.x_ring.mut_bytes_at(self.frames, x_head, len))
145    }
146    /// Peeks at the first available chunk in the ring without advancing the head.
147    ///
148    /// This function finds the first descriptor in the range of available descriptors
149    /// and returns a byte slice into the UMEM for reading (RX).
150    ///
151    /// # Returns
152    ///
153    /// A `Result` containing a byte slice and its corresponding descriptor index.
154    #[inline]
155    pub fn peek(&mut self) -> Result<&[u8], RingError> {
156        self.peek_(0)
157    }
158
159    /// Peeks at the `index`-th available chunk in the ring without advancing the head.
160    ///
161    /// This function finds the `index`-th descriptor in the range of available descriptors
162    /// and returns a byte slice into the UMEM for reading (RX).
163    ///
164    /// # Arguments
165    ///
166    /// * `index` - The index in the range of available descriptors.
167    ///
168    /// # Returns
169    ///
170    /// A `Result` containing a byte slice and its corresponding descriptor index.
171    #[inline]
172    pub fn peek_at(&mut self, index: usize) -> Result<&[u8], RingError> {
173        self.peek_(index)
174    }
175
176    /// Seeks to the next available descriptor in the ring and peeks at the descriptor
177    /// without advancing the head.
178    ///
179    /// This function calls `seek_` with a count of 1, and then calls `peek_` with a length
180    /// of the descriptor length. It returns a byte slice into the UMEM for reading (RX).
181    ///
182    /// # Returns
183    ///
184    /// A `Result` containing a byte slice and its corresponding descriptor index.
185    pub fn seek_and_peek(&mut self) -> Result<&[u8], RingError> {
186        self.seek_(1)?;
187        self.peek_(0)
188    }
189}