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}