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}