@@ -45,6 +45,11 @@ impl Memory {
45
45
}
46
46
47
47
/// A pointer to a single descriptor in a group
48
+ ///
49
+ /// Fundamentally, this is similar to something like `Arc<DescriptorInner>`. However,
50
+ /// it doesn't use its own allocation for the Arc layout, and instead embeds the reference
51
+ /// counts in the descriptor data. This avoids allocating a new `Arc` every time a packet
52
+ /// is received and instead allows the descriptor to be reused.
48
53
pub ( super ) struct Descriptor {
49
54
ptr : NonNull < DescriptorInner > ,
50
55
phantom : PhantomData < DescriptorInner > ,
@@ -76,7 +81,7 @@ impl Descriptor {
76
81
77
82
#[ inline]
78
83
fn data ( & self ) -> NonNull < u8 > {
79
- self . inner ( ) . data
84
+ self . inner ( ) . payload
80
85
}
81
86
82
87
#[ inline]
@@ -146,26 +151,43 @@ unsafe impl Send for Descriptor {}
146
151
unsafe impl Sync for Descriptor { }
147
152
148
153
pub ( super ) struct DescriptorInner {
154
+ /// An identifier for the descriptor
155
+ ///
156
+ /// This can be used by the pool implementation to map the descriptor to an internal
157
+ /// detail, e.g. in AF_XDP it passes around UMEM offsets.
149
158
id : u64 ,
159
+ /// The pointer to the descriptor address
150
160
address : NonNull < Addr > ,
151
- data : NonNull < u8 > ,
152
-
161
+ /// The pointer to the descriptor payload
162
+ payload : NonNull < u8 > ,
163
+ /// The number of active references for this descriptor.
164
+ ///
165
+ /// This refcount allows for splitting descriptors into multiple segments
166
+ /// and then correctly freeing the descriptor once the last segment is dropped.
153
167
references : AtomicUsize ,
154
-
168
+ /// A reference back to the memory region that owns the descriptor
155
169
memory : NonNull < Memory > ,
156
170
}
157
171
158
172
impl DescriptorInner {
159
- pub ( super ) fn new (
173
+ /// # Safety
174
+ ///
175
+ /// `address` must be initialized.
176
+ ///
177
+ /// `payload` must point to a valid region of memory that is at least `capacity` bytes
178
+ /// long. Additionally it must be initialized to valid memory.
179
+ ///
180
+ /// `memory` must be initialized.
181
+ pub ( super ) unsafe fn new (
160
182
id : u64 ,
161
183
address : NonNull < Addr > ,
162
- data : NonNull < u8 > ,
184
+ payload : NonNull < u8 > ,
163
185
memory : NonNull < Memory > ,
164
186
) -> Self {
165
187
Self {
166
188
id,
167
189
address,
168
- data ,
190
+ payload ,
169
191
references : AtomicUsize :: new ( 0 ) ,
170
192
memory,
171
193
}
@@ -184,7 +206,8 @@ impl DescriptorInner {
184
206
debug_assert_ne ! ( mem_refs, 0 , "reference count underflow" ) ;
185
207
186
208
// if the free_list is still active (the allocator hasn't dropped) then just push the id
187
- // TODO Weak::upgrade is a bit expensive since it clones the `Arc`, only to drop it again
209
+ // The `upgrade` acts as a lock for freeing the `Memory` instance, in the case that the
210
+ // free list has been dropped by the allocator.
188
211
if let Some ( free_list) = memory. free_list . upgrade ( ) {
189
212
free_list. free ( Descriptor {
190
213
ptr : desc. ptr ,
@@ -214,6 +237,11 @@ impl DescriptorInner {
214
237
215
238
/// An unfilled packet
216
239
pub struct Unfilled {
240
+ /// The inner raw descriptor.
241
+ ///
242
+ /// This needs to be an [`Option`] to allow for both consuming the descriptor
243
+ /// into a [`Filled`] after receiving a packet or dropping the [`Unfilled`] and
244
+ /// releasing it back into the packet pool.
217
245
desc : Option < Descriptor > ,
218
246
}
219
247
@@ -225,6 +253,7 @@ impl fmt::Debug for Unfilled {
225
253
}
226
254
227
255
impl Unfilled {
256
+ /// Creates an [`Unfilled`] descriptor from a raw [`Descriptor`].
228
257
#[ inline]
229
258
pub ( super ) fn from_descriptor ( desc : Descriptor ) -> Self {
230
259
desc. upgrade ( ) ;
@@ -241,7 +270,10 @@ impl Unfilled {
241
270
let inner = desc. inner ( ) ;
242
271
let addr = unsafe { & mut * inner. address . as_ptr ( ) } ;
243
272
let capacity = inner. capacity ( ) as usize ;
244
- let data = unsafe { core:: slice:: from_raw_parts_mut ( inner. data . as_ptr ( ) , capacity) } ;
273
+ let data = unsafe {
274
+ // SAFETY: a pool implementation is required to initialize all payload bytes
275
+ core:: slice:: from_raw_parts_mut ( inner. payload . as_ptr ( ) , capacity)
276
+ } ;
245
277
let iov = IoSliceMut :: new ( data) ;
246
278
let mut cmsg = cmsg:: Receiver :: default ( ) ;
247
279
@@ -282,10 +314,18 @@ impl Drop for Unfilled {
282
314
}
283
315
}
284
316
317
+ /// A filled packet
285
318
pub struct Filled {
319
+ /// The raw descriptor
286
320
desc : Descriptor ,
321
+ /// The offset into the payload
322
+ ///
323
+ /// This allows for splitting up a filled packet into multiple segments, while still ensuring
324
+ /// exclusive access to a region.
287
325
offset : u16 ,
326
+ /// The filled length of the payload
288
327
len : u16 ,
328
+ /// The ECN marking of the packet
289
329
ecn : ExplicitCongestionNotification ,
290
330
}
291
331
@@ -338,6 +378,7 @@ impl Filled {
338
378
#[ inline]
339
379
pub fn payload ( & self ) -> & [ u8 ] {
340
380
unsafe {
381
+ // SAFETY: the descriptor has been filled through the [`Unfilled`] API
341
382
let ptr = self . desc . data ( ) . as_ptr ( ) . add ( self . offset as _ ) ;
342
383
let len = self . len as usize ;
343
384
core:: slice:: from_raw_parts ( ptr, len)
@@ -349,6 +390,8 @@ impl Filled {
349
390
#[ inline]
350
391
pub fn payload_mut ( & mut self ) -> & mut [ u8 ] {
351
392
unsafe {
393
+ // SAFETY: the descriptor has been filled through the [`Unfilled`] API
394
+ // SAFETY: the `offset` + `len` are exclusively owned by this reference
352
395
let ptr = self . desc . data ( ) . as_ptr ( ) . add ( self . offset as _ ) ;
353
396
let len = self . len as usize ;
354
397
core:: slice:: from_raw_parts_mut ( ptr, len)
@@ -374,8 +417,12 @@ impl Filled {
374
417
let ecn = self . ecn ;
375
418
self . offset += at;
376
419
self . len -= at;
420
+
421
+ // update the reference counts for the descriptor
422
+ let desc = self . desc . clone_filled ( ) ;
423
+
377
424
Self {
378
- desc : self . desc . clone_filled ( ) ,
425
+ desc,
379
426
offset,
380
427
len : at,
381
428
ecn,
@@ -408,6 +455,8 @@ impl Filled {
408
455
impl Drop for Filled {
409
456
#[ inline]
410
457
fn drop ( & mut self ) {
458
+ // decrement the reference count, which may put the descriptor back into the pool once
459
+ // it reaches 0
411
460
self . desc . drop_filled ( )
412
461
}
413
462
}
0 commit comments