Skip to main content

netdevice_client/session/buffer/
pool.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Fuchsia netdevice buffer pool.
6
7use fuchsia_sync::Mutex;
8use futures::task::AtomicWaker;
9use std::borrow::Borrow;
10use std::collections::VecDeque;
11use std::convert::TryInto as _;
12use std::fmt::Debug;
13use std::io::{Read, Seek, SeekFrom, Write};
14use std::mem::MaybeUninit;
15use std::num::{NonZeroU16, TryFromIntError};
16use std::ops::{Deref, DerefMut};
17use std::ptr::NonNull;
18use std::sync::Arc;
19use std::sync::atomic::{self, AtomicBool, AtomicU64};
20use std::task::Poll;
21
22use arrayvec::ArrayVec;
23use explicit::ResultExt as _;
24use fidl_fuchsia_hardware_network as netdev;
25use fuchsia_runtime::vmar_root_self;
26use futures::channel::oneshot::{Receiver, Sender, channel};
27
28use super::{ChainLength, DescId, DescRef, DescRefMut, Descriptors};
29use crate::error::{Error, Result};
30use crate::session::tx::TxVmoIndex;
31use crate::session::{BufferLayout, Config, DEFAULT_VMO_ID, Pending, Port};
32
33/// Responsible for managing [`Buffer`]s for a [`Session`](crate::session::Session).
34pub(in crate::session) struct Pool {
35    /// Base address of the pool.
36    // Note: This field requires us to manually implement `Sync` and `Send`.
37    base: NonNull<u8>,
38    /// The descriptors allocated for the pool.
39    descriptors: Descriptors,
40    /// Shared state for allocation.
41    pub(in crate::session) tx_alloc_state: Mutex<TxAllocState>,
42    /// The free rx descriptors pending to be sent to driver.
43    pub(in crate::session) rx_pending: Mutex<Pending<Rx>>,
44    /// The buffer layout.
45    buffer_layout: BufferLayout,
46    /// State-keeping allowing sessions to handle rx leases.
47    rx_leases: RxLeaseHandlingState,
48    /// All VMOs are mapped contiguously starting from `base`. This list records
49    /// offsets from `base` each VMO is mapped at. The last element is the size
50    /// of the entire allocation.
51    vmo_offsets: Vec<usize>,
52    /// VMO IDs that support dynamic decommitment. The VMO IDs are contiguous
53    /// and sorted. This list is guaranteed to be non-empty if
54    /// `decommittable_tx_vmar` is [`Some`].
55    pub(in crate::session) decommittable_tx_vmo_ids: Vec<netdev::VmoId>,
56    /// Handle used to decommit Tx-only VMOs. [`None`] when single VMO mode is
57    /// in use (ie. all data is in one VMO).
58    decommittable_tx_vmar: Option<zx::Vmar>,
59}
60
61// `Pool` is `Send` and `Sync`, and this allows the compiler to deduce `Buffer`
62// to be `Send`. These impls are safe because we can safely share `Pool` and
63// `&Pool`: the implementation would never allocate the same buffer to two
64// callers at the same time.
65unsafe impl Send for Pool {}
66unsafe impl Sync for Pool {}
67
68/// The shared state which keeps track of available buffers and tx buffers.
69pub(in crate::session) struct TxAllocState {
70    /// All pending tx allocation requests.
71    requests: VecDeque<TxAllocReq>,
72    free_lists: Vec<TxFreeList>,
73    /// Index into `free_lists` that holds the first free list with available
74    /// buffers. If there are no available buffers, this is equal to
75    /// `free_lists.len()`.
76    first_available_index: usize,
77    /// Current number of buffers in use.
78    total_in_use: u16,
79    /// Peak number of buffers in use during the last measuring window. Cleared
80    /// when `sample_peak_buffer_usage` is called.
81    peak_in_use: u16,
82}
83
84impl TxAllocState {
85    fn try_alloc(
86        &mut self,
87        num_parts: ChainLength,
88        descriptors: &Descriptors,
89    ) -> Option<Chained<DescId<Tx>>> {
90        for free_list in self.free_lists[self.first_available_index..].iter_mut() {
91            if let Some(allocated) = free_list.try_alloc(num_parts, descriptors) {
92                while self.first_available_index < self.free_lists.len()
93                    && self.free_lists[self.first_available_index].free == 0
94                {
95                    self.first_available_index += 1;
96                }
97                self.total_in_use += u16::from(num_parts.get());
98                self.peak_in_use = self.peak_in_use.max(self.total_in_use);
99                return Some(allocated);
100            }
101        }
102        None
103    }
104
105    pub(in crate::session) fn sample_peak_buffer_usage(&mut self) -> u16 {
106        std::mem::replace(&mut self.peak_in_use, 0)
107    }
108
109    pub(in crate::session) fn is_tx_vmo_index_in_use(&self, idx: TxVmoIndex) -> bool {
110        self.free_lists[idx].max_free > self.free_lists[idx].free
111    }
112}
113
114/// We use a linked list to maintain the tx free descriptors - they are linked
115/// through their `nxt` fields, note this differs from the chaining expected
116/// by the network device protocol:
117/// - You can chain more than [`netdev::MAX_DESCRIPTOR_CHAIN`] descriptors
118///   together.
119/// - the free-list ends when the `nxt` field is 0xff, while the normal chain
120///   ends when `chain_length` becomes 0.
121struct TxFreeList {
122    /// The head of a linked list of available descriptors that can be allocated
123    /// for tx.
124    head: Option<DescId<Tx>>,
125    /// How many free descriptors are there in this list.
126    free: u16,
127    /// Maximum possible number of free descriptors this list can have.
128    max_free: u16,
129}
130
131/// The created [`Pool`] and its backing [`zx::Vmo`]s.
132pub(in crate::session) struct CreatedPool {
133    pub pool: Arc<Pool>,
134    pub descriptors_vmo: zx::Vmo,
135    pub data_vmos: Vec<zx::Vmo>,
136}
137
138impl Pool {
139    /// Creates a new [`Pool`] and its backing [`zx::Vmo`]s.
140    ///
141    /// When `config.multi_vmo` is true, `data_vmos` contains one RX VMO
142    /// followed by multiple TX VMOs. These VMOs are mapped to `base`
143    /// contiguously, with the RX VMO starting at `base` and the TX VMOs
144    /// starting after the RX VMO. `vmo_offsets` contains the offset of each VMO
145    /// in the `base` address space: `vmo_offsets[0]` is 0 and
146    /// `vmo_offset[vmo_offset.len()-1]` is the total length of the mapped
147    /// address space in bytes.
148    ///
149    /// When `config.multi_vmo` is false, `data_vmos` contains only one VMO for
150    /// both RX and TX.
151    pub(in crate::session) fn new(config: Config) -> Result<CreatedPool> {
152        let create_and_name_vmo = |size: u64, name: &zx::Name| -> Result<zx::Vmo> {
153            let vmo = zx::Vmo::create(size).map_err(|status| Error::Vmo("create", status))?;
154            vmo.set_name(&name).map_err(|status| Error::Vmo("set_name", status))?;
155            Ok(vmo)
156        };
157
158        let descriptor_count = config
159            .num_rx_buffers
160            .get()
161            .checked_add(config.num_tx_buffers().get())
162            .ok_or(Error::Config("too many descriptors".to_string()))?;
163        let descriptor_vmo_size =
164            u64::try_from(super::NETWORK_DEVICE_DESCRIPTOR_LENGTH * usize::from(descriptor_count))
165                .expect("vmo_size overflows u64");
166        const DESCRIPTORS_VMO_NAME: zx::Name =
167            const_unwrap::const_unwrap_result(zx::Name::new("netdevice:descriptors"));
168        let descriptors_vmo = create_and_name_vmo(descriptor_vmo_size, &DESCRIPTORS_VMO_NAME)?;
169
170        let Config {
171            buffer_stride,
172            num_rx_buffers,
173            tx_vmos,
174            options,
175            buffer_layout,
176            buffer_usage_sample_interval: _,
177        } = config;
178        let num_tx_buffers = {
179            let sum: u16 = tx_vmos.iter().map(|v| v.num_buffers).sum();
180            NonZeroU16::new(sum).expect("num_tx_buffers is zero")
181        };
182        let num_buffers = num_rx_buffers.get() + num_tx_buffers.get();
183        let single_data_vmo = tx_vmos.len() == 1 && tx_vmos[0].vmo_id == DEFAULT_VMO_ID;
184        let decommittable_tx_vmo_ids = if single_data_vmo {
185            vec![]
186        } else {
187            tx_vmos.iter().map(|v| v.vmo_id).collect::<Vec<_>>()
188        };
189
190        let page_size = u64::from(zx::system_get_page_size());
191        let data_vmos = if single_data_vmo {
192            const VMO_NAME: zx::Name =
193                const_unwrap::const_unwrap_result(zx::Name::new("netdevice:data"));
194            let size = (buffer_stride.get() * u64::from(num_buffers)).next_multiple_of(page_size);
195            let data_vmo = create_and_name_vmo(size, &VMO_NAME)?;
196            vec![data_vmo]
197        } else {
198            const RX_VMO_NAME: zx::Name =
199                const_unwrap::const_unwrap_result(zx::Name::new("netdevice:rx_data"));
200            const TX_VMO_NAME: zx::Name =
201                const_unwrap::const_unwrap_result(zx::Name::new("netdevice:tx_data"));
202
203            let rx_size =
204                (buffer_stride.get() * u64::from(num_rx_buffers.get())).next_multiple_of(page_size);
205            let rx_vmo = create_and_name_vmo(rx_size, &RX_VMO_NAME)?;
206
207            std::iter::once(Ok(rx_vmo))
208                .chain(tx_vmos.iter().map(|vmo_config| {
209                    let size = (buffer_stride.get() * u64::from(vmo_config.num_buffers))
210                        .next_multiple_of(page_size);
211                    create_and_name_vmo(size, &TX_VMO_NAME)
212                }))
213                .collect::<Result<Vec<_>>>()?
214        };
215
216        let (descriptors, mut tx_free, mut rx_free) =
217            Descriptors::new(&tx_vmos, num_rx_buffers, buffer_stride, &descriptors_vmo)?;
218
219        for rx_desc in rx_free.iter_mut() {
220            descriptors.borrow_mut(rx_desc).initialize(
221                ChainLength::ZERO,
222                0,
223                buffer_layout.length.try_into().unwrap(),
224                0,
225            );
226        }
227
228        let mut total_len = 0;
229        let mut vmo_offsets = vec![0];
230
231        for vmo in &data_vmos {
232            total_len +=
233                usize::try_from(vmo.get_size().map_err(|status| Error::VmoSize("data", status))?)
234                    .expect("usize must be able to hold u64");
235            vmo_offsets.push(total_len);
236        }
237
238        // Use variable shadowing to prevent any modification from now on.
239        let (total_len, vmo_offsets) = (total_len, vmo_offsets);
240
241        let map_data_vmo = |vmar: &zx::Vmar,
242                            data_vmo: usize,
243                            vmar_start_offset: usize|
244         -> Result<()> {
245            let offset = vmo_offsets[data_vmo] - vmar_start_offset;
246            let len = vmo_offsets[data_vmo + 1] - vmo_offsets[data_vmo];
247            let _addr = vmar
248                .map(
249                    offset,
250                    &data_vmos[data_vmo],
251                    0,
252                    len,
253                    zx::VmarFlags::SPECIFIC | zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE,
254                )
255                .map_err(|status| Error::Map("map data vmo", status))?;
256            Ok(())
257        };
258
259        let (vmar, vmar_start) = vmar_root_self()
260            .allocate(
261                0,
262                total_len,
263                zx::VmarFlags::CAN_MAP_READ
264                    | zx::VmarFlags::CAN_MAP_WRITE
265                    | zx::VmarFlags::CAN_MAP_SPECIFIC,
266            )
267            .map_err(|status| Error::Map("allocate vmar", status))?;
268        let base = NonNull::new(vmar_start as *mut u8).expect("must not be null");
269
270        map_data_vmo(&vmar, 0, 0)?;
271
272        let decommittable_tx_vmar = (!single_data_vmo)
273            .then(|| {
274                // TODO(https://fxbug.dev/438527741): Remove this constant when Rx path
275                // supports dynamic VMO management.
276                const NUM_RX_VMO: usize = 1;
277                let rx_size = vmo_offsets[NUM_RX_VMO];
278                let tx_vmar_len = total_len - rx_size;
279                let (tx_vmar, _tx_vmar_base) = vmar
280                    .allocate(
281                        rx_size,
282                        tx_vmar_len,
283                        zx::VmarFlags::SPECIFIC
284                            | zx::VmarFlags::CAN_MAP_READ
285                            | zx::VmarFlags::CAN_MAP_WRITE
286                            | zx::VmarFlags::CAN_MAP_SPECIFIC,
287                    )
288                    .map_err(|status| Error::Map("allocate tx-vmar", status))?;
289                for i in NUM_RX_VMO..data_vmos.len() {
290                    map_data_vmo(&tx_vmar, i, rx_size)?;
291                }
292                Ok::<_, Error>(tx_vmar)
293            })
294            .transpose()?;
295
296        let mut free_lists = Vec::new();
297        for vmo_config in &tx_vmos {
298            let head = tx_free.drain(..usize::from(vmo_config.num_buffers)).rev().fold(
299                None,
300                |head, mut curr| {
301                    descriptors.borrow_mut(&mut curr).set_nxt(head);
302                    assert_eq!(descriptors.borrow(&curr).vmo_id(), vmo_config.vmo_id);
303                    Some(curr)
304                },
305            );
306            free_lists.push(TxFreeList {
307                head,
308                free: vmo_config.num_buffers,
309                max_free: vmo_config.num_buffers,
310            });
311        }
312
313        let tx_alloc_state = Mutex::new(TxAllocState {
314            free_lists,
315            requests: VecDeque::new(),
316            first_available_index: 0,
317            total_in_use: 0,
318            peak_in_use: 0,
319        });
320
321        let pool = Arc::new(Pool {
322            base,
323            descriptors,
324            tx_alloc_state,
325            rx_pending: Mutex::new(Pending::new(rx_free)),
326            buffer_layout,
327            rx_leases: RxLeaseHandlingState::new_with_flags(options),
328            vmo_offsets,
329            decommittable_tx_vmo_ids,
330            decommittable_tx_vmar,
331        });
332
333        Ok(CreatedPool { pool, descriptors_vmo, data_vmos })
334    }
335
336    /// Allocates `num_parts` tx descriptors.
337    ///
338    /// It will block if there are not enough descriptors. Note that the
339    /// descriptors are not initialized, you need to call [`AllocGuard::init()`]
340    /// on the returned [`AllocGuard`] if you want to send it to the driver
341    /// later.
342    pub(in crate::session) async fn alloc_tx(
343        self: &Arc<Self>,
344        num_parts: ChainLength,
345    ) -> AllocGuard<Tx> {
346        let receiver = {
347            let mut state = self.tx_alloc_state.lock();
348            match state.try_alloc(num_parts, &self.descriptors) {
349                Some(allocated) => {
350                    return AllocGuard::new(allocated, self.clone());
351                }
352                None => {
353                    let (request, receiver) = TxAllocReq::new(num_parts);
354                    state.requests.push_back(request);
355                    receiver
356                }
357            }
358        };
359        // The sender must not be dropped.
360        receiver.await.unwrap()
361    }
362
363    /// Tries to allocate a [`SinglePartTxBuffer`].
364    ///
365    /// Returns `Ok(None)` if there is no available buffer, or `Err(Error::TxLength)`
366    /// if the requested size cannot meet the device requirement.
367    pub(in crate::session) fn try_alloc_single_part_tx_buffer(
368        self: &Arc<Self>,
369        num_bytes: usize,
370    ) -> Result<Option<SinglePartTxBuffer>> {
371        let BufferLayout { min_tx_data: _, min_tx_head, min_tx_tail, length: buffer_length } =
372            self.buffer_layout;
373        if num_bytes > buffer_length - usize::from(min_tx_head) - usize::from(min_tx_tail) {
374            return Err(Error::TxLength);
375        }
376        self.tx_alloc_state
377            .lock()
378            .try_alloc(ChainLength::try_from(1u8).unwrap(), &self.descriptors)
379            .map(|allocated| -> Result<SinglePartTxBuffer> {
380                let mut alloc = AllocGuard::new(allocated, self.clone());
381                alloc.init(num_bytes)?;
382                let buffer = Buffer::from(alloc);
383                Ok(SinglePartTxBuffer::new(buffer, num_bytes).expect("must be single part"))
384            })
385            .transpose()
386    }
387
388    /// Allocates a tx [`Buffer`].
389    ///
390    /// The returned buffer will have `num_bytes` as its capacity, the method
391    /// will block if there are not enough buffers. An error will be returned if
392    /// the requested size cannot meet the device requirement, for example, if
393    /// the size of the head or tail region will become unrepresentable in u16.
394    pub(in crate::session) async fn alloc_tx_buffer(
395        self: &Arc<Self>,
396        num_bytes: usize,
397    ) -> Result<Buffer<Tx>> {
398        self.alloc_tx_buffers(num_bytes).await?.next().unwrap()
399    }
400
401    /// Waits for at least one TX buffer to be available and returns an iterator
402    /// of buffers with `num_bytes` as capacity.
403    ///
404    /// The returned iterator is guaranteed to yield at least one item (though
405    /// it might be an error if the requested size cannot meet the device
406    /// requirement).
407    ///
408    /// # Note
409    ///
410    /// Given a `Buffer<Tx>` is returned to the pool when it's dropped, the
411    /// returned iterator will seemingly yield infinite items if the yielded
412    /// `Buffer`s are dropped while iterating.
413    pub(in crate::session) async fn alloc_tx_buffers<'a>(
414        self: &'a Arc<Self>,
415        num_bytes: usize,
416    ) -> Result<impl Iterator<Item = Result<Buffer<Tx>>> + 'a> {
417        let BufferLayout { min_tx_data, min_tx_head, min_tx_tail, length: buffer_length } =
418            self.buffer_layout;
419        let tx_head = usize::from(min_tx_head);
420        let tx_tail = usize::from(min_tx_tail);
421        let total_bytes = num_bytes.max(min_tx_data) + tx_head + tx_tail;
422        let num_parts = (total_bytes + buffer_length - 1) / buffer_length;
423        let chain_length = ChainLength::try_from(num_parts)?;
424        let first = self.alloc_tx(chain_length).await;
425        let iter = std::iter::once(first)
426            .chain(std::iter::from_fn(move || {
427                let mut state = self.tx_alloc_state.lock();
428                state
429                    .try_alloc(chain_length, &self.descriptors)
430                    .map(|allocated| AllocGuard::new(allocated, self.clone()))
431            }))
432            // Fuse afterwards so we're guaranteeing we can't see a new entry
433            // after having yielded `None` once.
434            .fuse()
435            .map(move |mut alloc| {
436                alloc.init(num_bytes)?;
437                Ok(alloc.into())
438            });
439        Ok(iter)
440    }
441
442    /// Frees rx descriptors.
443    pub(in crate::session) fn free_rx(&self, descs: impl IntoIterator<Item = DescId<Rx>>) {
444        self.rx_pending.lock().extend(descs.into_iter().map(|mut desc| {
445            self.descriptors.borrow_mut(&mut desc).initialize(
446                ChainLength::ZERO,
447                0,
448                self.buffer_layout.length.try_into().unwrap(),
449                0,
450            );
451            desc
452        }));
453    }
454
455    /// Frees tx descriptors.
456    ///
457    /// # Panics
458    ///
459    /// Panics if given an empty chain.
460    fn free_tx(self: &Arc<Self>, chain: Chained<DescId<Tx>>) {
461        // We store any pending request that need to be fulfilled in the stack
462        // here, to fulfill them only once we drop the lock, guaranteeing an
463        // AllocGuard can't be dropped while the lock is held.
464        let mut to_fulfill = ArrayVec::<
465            (TxAllocReq, AllocGuard<Tx>),
466            { netdev::MAX_DESCRIPTOR_CHAIN as usize },
467        >::new();
468
469        let mut state = self.tx_alloc_state.lock();
470        state.total_in_use -= u16::from(chain.len.get());
471        {
472            let vmo_id =
473                self.descriptors.borrow(chain.first().expect("chain is not empty")).vmo_id();
474            let idx = self.free_list_index(vmo_id);
475            if idx < state.first_available_index {
476                state.first_available_index = idx;
477            }
478
479            let mut descs = chain.into_iter();
480            state.free_lists[idx].free += u16::try_from(descs.len()).unwrap();
481            let head = descs.next();
482            let old_head = std::mem::replace(&mut state.free_lists[idx].head, head);
483            let mut tail = descs.last();
484            let mut tail_ref = self.descriptors.borrow_mut(
485                tail.as_mut().unwrap_or_else(|| state.free_lists[idx].head.as_mut().unwrap()),
486            );
487            tail_ref.set_nxt(old_head);
488        }
489
490        // After putting the chain back into the free list, we try to fulfill
491        // any pending tx allocation requests.
492        while let Some(req) = state.requests.front() {
493            // Skip a request that we know is canceled.
494            //
495            // This is an optimization for long-ago dropped requests, since the
496            // receiver side can be dropped between here and fulfillment later.
497            if req.sender.is_canceled() {
498                let _cancelled: Option<TxAllocReq> = state.requests.pop_front();
499                continue;
500            }
501            let size = req.size;
502            match state.try_alloc(size, &self.descriptors) {
503                Some(descs) => {
504                    // The unwrap is safe because we know requests is not empty.
505                    let req = state.requests.pop_front().unwrap();
506                    to_fulfill.push((req, AllocGuard::new(descs, self.clone())));
507
508                    // If we're full temporarily release the lock to go again
509                    // later. Fulfilling a request must _always_ be done without
510                    // holding the lock.
511                    if to_fulfill.is_full() {
512                        drop(state);
513                        for (req, alloc) in to_fulfill.drain(..) {
514                            req.fulfill(alloc)
515                        }
516                        state = self.tx_alloc_state.lock();
517                    }
518                }
519                None => break,
520            }
521        }
522
523        // Make sure we're not holding the state lock when fulfilling requests.
524        drop(state);
525        // Fulfill any ready requests.
526        for (req, alloc) in to_fulfill {
527            req.fulfill(alloc)
528        }
529    }
530
531    /// Frees the completed tx descriptors chained by head to the pool.
532    ///
533    /// Call this function when the driver hands back a completed tx descriptor.
534    pub(in crate::session) fn tx_completed(self: &Arc<Self>, head: DescId<Tx>) -> Result<()> {
535        let chain = self.descriptors.chain(head).collect::<Result<Chained<_>>>()?;
536        Ok(self.free_tx(chain))
537    }
538
539    /// Creates a [`Buffer<Rx>`] corresponding to the completed rx descriptors.
540    ///
541    /// Whenever the driver hands back a completed rx descriptor, this function
542    /// can be used to create the buffer that is represented by those chained
543    /// descriptors.
544    pub(in crate::session) fn rx_completed(
545        self: &Arc<Self>,
546        head: DescId<Rx>,
547    ) -> Result<Buffer<Rx>> {
548        let descs = self.descriptors.chain(head).collect::<Result<Chained<_>>>()?;
549        let alloc = AllocGuard::new(descs, self.clone());
550        Ok(alloc.into())
551    }
552
553    fn get_slice_layout<K: AllocKind>(&self, desc: &super::Descriptor<K>) -> (usize, usize) {
554        let vmo_id = usize::from(desc.vmo_id());
555        if vmo_id >= self.vmo_offsets.len() - 1 {
556            panic!("invalid vmo_id {} for vmo_offsets of len {}", vmo_id, self.vmo_offsets.len());
557        }
558        let vmo_offset = self.vmo_offsets[vmo_id];
559        let next_vmo_offset = self.vmo_offsets[vmo_id + 1];
560
561        let desc_offset = desc.offset();
562        let head_len = u64::from(desc.head_length());
563        let data_len = u64::from(desc.data_length());
564
565        let total_offset = desc_offset
566            .checked_add(head_len)
567            .and_then(|o| usize::try_from(o).ok())
568            .and_then(|o| o.checked_add(vmo_offset))
569            .unwrap_or_else(|| panic!("offset calculation overflowed"));
570
571        let len =
572            usize::try_from(data_len).unwrap_or_else(|_| panic!("data_length overflowed usize"));
573
574        let end = total_offset
575            .checked_add(len)
576            .unwrap_or_else(|| panic!("end offset calculation overflowed"));
577
578        if end > next_vmo_offset {
579            panic!("slice end {} out of VMO bounds {}", end, next_vmo_offset);
580        }
581
582        (total_offset, len)
583    }
584
585    fn get_slice<'a, K: AllocKind>(&self, desc: &'a DescId<K>) -> &'a [u8] {
586        let desc = self.descriptors.borrow(desc);
587        let (offset, len) = self.get_slice_layout(&desc);
588        // Safety: The descriptor is describing a buffer from this pool. It must
589        // be valid to create a slice into that region. We hold a immutable
590        // reference to the underlying descriptor, this means no one else should
591        // have mutable reference to this memory region.
592        unsafe {
593            let ptr = self.base.as_ptr().add(offset);
594            std::slice::from_raw_parts(ptr, len)
595        }
596    }
597
598    fn get_slice_mut<'a, K: AllocKind>(&self, desc: &'a mut DescId<K>) -> &'a mut [u8] {
599        let desc = self.descriptors.borrow_mut(desc);
600        let (offset, len) = self.get_slice_layout(&*desc);
601        // Safety: The descriptor is describing a buffer from this pool. It must
602        // be valid to create a slice into that region. We hold a mutable
603        // reference to the underlying descriptor, this means we are currently
604        // the only one has access to this memory region.
605        unsafe {
606            let ptr = self.base.as_ptr().add(offset);
607            std::slice::from_raw_parts_mut(ptr, len)
608        }
609    }
610
611    pub(in crate::session) fn decommit_tx_vmo(&self, tx_vmo_idx: TxVmoIndex) -> Result<()> {
612        let tx_vmar = self
613            .decommittable_tx_vmar
614            .as_ref()
615            .ok_or(Error::Vmo("decommit", zx::Status::NOT_SUPPORTED))?;
616        let vmo_idx = tx_vmo_idx + usize::from(self.decommittable_tx_vmo_ids[0]);
617        let start_offset = self.vmo_offsets[vmo_idx];
618        let end_offset = self.vmo_offsets[vmo_idx + 1];
619        let len = end_offset - start_offset;
620        let addr = self.base.addr().get() + start_offset;
621        tx_vmar
622            .op_range(zx::VmarOp::DECOMMIT, addr, len)
623            .map_err(|status| Error::Vmo("decommit", status))
624    }
625
626    pub(in crate::session) fn has_decommittable_tx_vmo(&self) -> bool {
627        self.decommittable_tx_vmar.is_some()
628    }
629
630    fn free_list_index(&self, vmo_id: u8) -> usize {
631        if self.decommittable_tx_vmo_ids.is_empty() {
632            // If we are in the single data VMO mode, there is only one free list.
633            0
634        } else {
635            // If we have multiple dedicated Tx VMOs, then free_lists[0] is used to
636            // track free buffers from VMO `decommittable_tx_vmo_ids[0]`. The VMO
637            // ids from `decommittable_tx_vmo_ids` are contiguous and sorted so
638            // we can just offset the vmo_id by the first vmo_id to get the
639            // index of the free list to use.
640            usize::from(vmo_id - self.decommittable_tx_vmo_ids[0])
641        }
642    }
643}
644
645impl Drop for Pool {
646    fn drop(&mut self) {
647        let bytes = *self.vmo_offsets.last().unwrap();
648        unsafe {
649            vmar_root_self()
650                .unmap(self.base.as_ptr() as usize, bytes)
651                .expect("failed to unmap VMO for Pool")
652        }
653    }
654}
655
656impl TxFreeList {
657    /// Tries to allocate tx descriptors.
658    ///
659    /// Returns [`None`] if there are not enough descriptors.
660    fn try_alloc(
661        &mut self,
662        num_parts: ChainLength,
663        descriptors: &Descriptors,
664    ) -> Option<Chained<DescId<Tx>>> {
665        if u16::from(num_parts.get()) > self.free {
666            return None;
667        }
668
669        let free_list = std::iter::from_fn(|| -> Option<DescId<Tx>> {
670            let new_head = self.head.as_ref().and_then(|head| {
671                let nxt = descriptors.borrow(head).nxt();
672                nxt.map(|id| unsafe {
673                    // Safety: This is the nxt field of head of the free list,
674                    // it must be a tx descriptor id.
675                    DescId::from_raw(id)
676                })
677            });
678            std::mem::replace(&mut self.head, new_head)
679        });
680        let allocated = free_list.take(num_parts.get().into()).collect::<Chained<_>>();
681        assert_eq!(allocated.len(), num_parts.into());
682        self.free -= u16::from(num_parts.get());
683        Some(allocated)
684    }
685}
686
687/// The buffer that can be used by the [`Session`](crate::session::Session).
688pub struct Buffer<K: AllocKind> {
689    /// The descriptors allocation.
690    alloc: AllocGuard<K>,
691}
692
693impl<K: AllocKind> Buffer<K> {
694    pub(in crate::session) fn vmo_id(&self) -> u8 {
695        // Safety: Must not have an empty allocation.
696        let desc_id = unsafe { self.alloc.descs.storage[0].assume_init_ref() };
697        self.alloc.pool.descriptors.borrow(desc_id).vmo_id()
698    }
699
700    /// Returns the length of data region of the buffer.
701    pub fn len(&self) -> usize {
702        self.parts().map(|s| s.len()).sum()
703    }
704
705    /// Returns an iterator over the data slices of the buffer parts.
706    fn parts(&self) -> impl Iterator<Item = &[u8]> + '_ {
707        self.alloc.descs.iter().map(|desc| self.alloc.pool.get_slice(desc))
708    }
709
710    /// Returns an iterator over the mutable valid data slices of the buffer parts.
711    fn parts_mut(&mut self) -> impl Iterator<Item = &mut [u8]> + '_ {
712        self.alloc.descs.iter_mut().map(|desc| self.alloc.pool.get_slice_mut(desc))
713    }
714
715    /// Leaks the underlying buffer descriptors to the driver.
716    pub(in crate::session) fn leak(mut self) -> DescId<K> {
717        let descs = std::mem::replace(&mut self.alloc.descs, Chained::empty());
718        descs.into_iter().next().unwrap()
719    }
720
721    /// Returns the buffer data as a slice.
722    pub fn as_slice(&self) -> Option<&[u8]> {
723        if self.alloc.len() != 1 {
724            return None;
725        }
726        self.parts().next()
727    }
728
729    /// Returns the buffer data as a mutable slice.
730    pub fn as_slice_mut(&mut self) -> Option<&mut [u8]> {
731        if self.alloc.len() != 1 {
732            return None;
733        }
734        self.parts_mut().next()
735    }
736
737    /// Returns a wrapper for read-only operations.
738    pub fn io(&self) -> BufferIORef<'_, K> {
739        let mut len = 0;
740        let parts: Chained<&[u8]> = self.parts().inspect(|s| len += s.len()).collect();
741        BufferIO { parts, pos: 0, len, _marker: std::marker::PhantomData }
742    }
743
744    /// Returns a wrapper for read-write operations.
745    pub fn io_mut(&mut self) -> BufferIOMut<'_, K> {
746        let mut len = 0;
747        let parts: Chained<&mut [u8]> = self.parts_mut().inspect(|s| len += s.len()).collect();
748        BufferIO { parts, pos: 0, len, _marker: std::marker::PhantomData }
749    }
750}
751
752/// A guard for mutating metadata on a Tx buffer.
753///
754/// Holds an exclusive borrow of the underlying descriptor (`DescRefMut`),
755/// ensuring that atomic reference counting is performed only once when obtaining
756/// and dropping this guard, rather than on every individual field update.
757pub struct TxMetadataMut<'a> {
758    desc: DescRefMut<'a, Tx>,
759}
760
761impl<'a> TxMetadataMut<'a> {
762    /// Sets the buffer's destination port.
763    pub fn set_port(&mut self, port: Port) {
764        self.desc.set_port(port);
765    }
766
767    /// Sets the frame type of the buffer.
768    pub fn set_frame_type(&mut self, frame_type: netdev::FrameType) {
769        self.desc.set_frame_type(frame_type);
770    }
771
772    /// Sets TxFlags of a Tx buffer.
773    pub fn set_tx_flags(&mut self, flags: netdev::TxFlags) {
774        self.desc.set_tx_flags(flags);
775    }
776
777    /// Sets the generic checksum offload metadata for this buffer.
778    pub fn set_generic_csum_offload(&mut self, start: u16, offset: u16) {
779        self.desc.set_generic_csum_offload(start, offset);
780    }
781}
782
783impl Buffer<Tx> {
784    /// Returns a guard for mutating TX buffer metadata.
785    pub fn meta_mut(&mut self) -> TxMetadataMut<'_> {
786        TxMetadataMut { desc: self.alloc.descriptor_mut() }
787    }
788
789    /// Shrinks the buffer.
790    ///
791    /// This method shrinks the buffer length to the larger of
792    ///   - requested new length
793    ///   - device required minimum Tx data length
794    ///
795    /// It is an error to try to increase the buffer length.
796    pub fn shrink_to(&mut self, mut new_len: usize) -> Result<()> {
797        let current_len = self.len();
798
799        if new_len > current_len {
800            return Err(Error::TxLength);
801        }
802
803        let min_tx_data = usize::from(self.alloc.pool.buffer_layout.min_tx_data);
804        new_len = new_len.max(min_tx_data);
805
806        let layouts = self.alloc.calculate_descriptor_layouts(new_len)?;
807
808        for (desc_id, DescriptorLayout { data_length, tail_length, .. }) in
809            self.alloc.descs.iter_mut().zip(layouts)
810        {
811            let mut descriptor = self.alloc.pool.descriptors.borrow_mut(desc_id);
812            descriptor.set_data_length(data_length);
813            descriptor.set_tail_length(tail_length);
814        }
815        Ok(())
816    }
817}
818
819/// The rx checksum offloading information.
820pub enum ChecksumRxOffloading {
821    /// N checksums were fully verified by the device.
822    Offloaded(NonZeroU16),
823}
824
825/// A guard for reading metadata on an Rx buffer.
826///
827/// Holds a shared borrow of the underlying descriptor (`DescRef`),
828/// ensuring that atomic reference counting is performed only once when obtaining
829/// and dropping this guard, rather than on every individual field access.
830pub struct RxMetadata<'a> {
831    desc: DescRef<'a, Rx>,
832}
833
834impl<'a> RxMetadata<'a> {
835    /// Retrieves RxFlags of an Rx Buffer.
836    pub fn rx_flags(&self) -> Result<netdev::RxFlags> {
837        self.desc.rx_flags()
838    }
839
840    /// Retrieves the checksum offloading information.
841    pub fn rx_checksum_offloading(&self) -> Option<ChecksumRxOffloading> {
842        self.desc.rx_checksum_offloading()
843    }
844
845    /// Retrieves the frame type of the buffer.
846    pub fn frame_type(&self) -> Result<netdev::FrameType> {
847        self.desc.frame_type()
848    }
849
850    /// Retrieves the buffer's source port.
851    pub fn port(&self) -> Port {
852        self.desc.port()
853    }
854}
855
856impl Buffer<Rx> {
857    /// Returns a guard for reading RX buffer metadata.
858    pub fn meta(&self) -> RxMetadata<'_> {
859        RxMetadata { desc: self.alloc.descriptor() }
860    }
861}
862
863impl<K: AllocKind> Debug for Buffer<K> {
864    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
865        let Self { alloc } = self;
866        f.debug_struct("Buffer").field("alloc", alloc).finish()
867    }
868}
869
870/// A witness type that proves the buffer is backed by one part only
871/// and thus can be converted into `&[u8]`.
872pub struct SinglePartTxBuffer(Buffer<Tx>);
873
874impl SinglePartTxBuffer {
875    /// Creates a new [`SinglePartTxBuffer`] from a [`Buffer<Tx>`] if it is
876    /// backed by one part only.
877    pub fn new(buffer: Buffer<Tx>, len: usize) -> Option<Self> {
878        if buffer.alloc.len() != 1 {
879            None
880        } else {
881            let cap = usize::try_from(buffer.alloc.descriptor().data_length())
882                .expect("u32 must fit in a usize");
883            if cap < len { None } else { Some(Self(buffer)) }
884        }
885    }
886
887    /// Converts back to a Tx buffer.
888    pub fn into_inner(self) -> Buffer<Tx> {
889        let Self(buffer) = self;
890        buffer
891    }
892}
893
894impl AsRef<[u8]> for SinglePartTxBuffer {
895    fn as_ref(&self) -> &[u8] {
896        // Safety: `SinglePartTxBuffer` is guaranteed to have exactly one part
897        // (verified on creation), so the first descriptor is always initialized.
898        let desc = unsafe { self.0.alloc.descs.storage[0].assume_init_ref() };
899        self.0.alloc.pool.get_slice(desc)
900    }
901}
902
903impl AsMut<[u8]> for SinglePartTxBuffer {
904    fn as_mut(&mut self) -> &mut [u8] {
905        // Safety: `SinglePartTxBuffer` is guaranteed to have exactly one part
906        // (verified on creation), so the first descriptor is always initialized.
907        let desc = unsafe { self.0.alloc.descs.storage[0].assume_init_mut() };
908        self.0.alloc.pool.get_slice_mut(desc)
909    }
910}
911
912impl packet::FragmentedBuffer for SinglePartTxBuffer {
913    fn len(&self) -> usize {
914        let desc = self.0.alloc.descriptor();
915        usize::try_from(desc.data_length()).expect("u32 must fit in a usize")
916    }
917
918    fn with_bytes<'a, R, F>(&'a self, f: F) -> R
919    where
920        F: for<'b> FnOnce(packet::FragmentedBytes<'b, 'a>) -> R,
921    {
922        f(packet::FragmentedBytes::new(&mut [self.as_ref()][..]))
923    }
924}
925
926/// A wrapper around [`Buffer`] for sequential I/O.
927///
928/// `T` must be a slice reference type, typically `&'a [u8]` for read-only
929/// operations, or `&'a mut [u8]` for read-write operations.
930pub struct BufferIO<T, K: AllocKind> {
931    parts: Chained<T>,
932    pos: usize,
933    len: usize,
934    _marker: std::marker::PhantomData<K>,
935}
936
937pub type BufferIORef<'a, K> = BufferIO<&'a [u8], K>;
938pub type BufferIOMut<'a, K> = BufferIO<&'a mut [u8], K>;
939
940impl<T> BufferIO<T, Tx>
941where
942    T: AsMut<[u8]>,
943{
944    /// Writes data from `src` into the TX buffer starting at the specified `offset`.
945    ///
946    /// This method is infallible. It returns the number of bytes successfully written.
947    ///
948    /// If the specified `offset` is greater than or equal to the total length of the
949    /// buffer, or if the buffer has no remaining capacity at the offset, `0` bytes
950    /// will be written.
951    ///
952    /// If `src` is larger than the remaining capacity of the buffer starting at
953    /// `offset`, a short write occurs: only the bytes that fit within the buffer
954    /// are written, and the returned value will be less than `src.len()`.
955    pub fn write_at(&mut self, mut offset: usize, src: &[u8]) -> usize {
956        let mut total = 0;
957
958        for slice in self.parts.iter_mut() {
959            let slice = slice.as_mut();
960            if offset < slice.len() {
961                let available = slice.len() - offset;
962                let to_copy = std::cmp::min(src.len() - total, available);
963                slice[offset..offset + to_copy].copy_from_slice(&src[total..total + to_copy]);
964                total += to_copy;
965                offset = 0;
966                if total == src.len() {
967                    break;
968                }
969            } else {
970                offset -= slice.len();
971            }
972        }
973        total
974    }
975}
976
977impl<T, K: AllocKind> BufferIO<T, K>
978where
979    T: AsRef<[u8]>,
980{
981    /// Reads data from the buffer starting at the specified `offset` into `dst`.
982    ///
983    /// This method is infallible. It returns the number of bytes successfully read.
984    ///
985    /// If the specified `offset` is greater than or equal to the total length of the
986    /// buffer, `0` bytes will be read.
987    ///
988    /// If the remaining data in the buffer starting at `offset` is less than the
989    /// size of `dst`, a short read occurs: only the available bytes are copied,
990    /// and the returned value will be less than `dst.len()`.
991    pub fn read_at(&self, mut offset: usize, dst: &mut [u8]) -> usize {
992        let mut total = 0;
993
994        for slice in self.parts.iter() {
995            let slice = slice.as_ref();
996            if offset < slice.len() {
997                let available = slice.len() - offset;
998                let to_copy = std::cmp::min(dst.len() - total, available);
999                dst[total..total + to_copy].copy_from_slice(&slice[offset..offset + to_copy]);
1000                total += to_copy;
1001                offset = 0;
1002                if total == dst.len() {
1003                    break;
1004                }
1005            } else {
1006                offset -= slice.len();
1007            }
1008        }
1009        total
1010    }
1011}
1012
1013/// A non-empty container that has at most [`netdev::MAX_DESCRIPTOR_CHAIN`] elements.
1014struct Chained<T> {
1015    storage: [MaybeUninit<T>; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1016    len: ChainLength,
1017}
1018
1019impl<T> Deref for Chained<T> {
1020    type Target = [T];
1021
1022    fn deref(&self) -> &Self::Target {
1023        // Safety: `self.storage[..self.len]` is already initialized.
1024        unsafe { std::mem::transmute(&self.storage[..self.len.into()]) }
1025    }
1026}
1027
1028impl<T> DerefMut for Chained<T> {
1029    fn deref_mut(&mut self) -> &mut Self::Target {
1030        // Safety: `self.storage[..self.len]` is already initialized.
1031        unsafe { std::mem::transmute(&mut self.storage[..self.len.into()]) }
1032    }
1033}
1034
1035impl<T> Drop for Chained<T> {
1036    fn drop(&mut self) {
1037        // Safety: `self.deref_mut()` is a slice of all initialized elements.
1038        unsafe {
1039            std::ptr::drop_in_place(self.deref_mut());
1040        }
1041    }
1042}
1043
1044impl<T: Debug> Debug for Chained<T> {
1045    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1046        f.debug_list().entries(self.iter()).finish()
1047    }
1048}
1049
1050impl<T> Chained<T> {
1051    #[allow(clippy::uninit_assumed_init)]
1052    fn empty() -> Self {
1053        // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
1054        // safe because the type we are claiming to have initialized here is a
1055        // bunch of `MaybeUninit`s, which do not require initialization.
1056        // TODO(https://fxbug.dev/42160423): use MaybeUninit::uninit_array once it
1057        // is stablized.
1058        // https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.uninit_array
1059        Self { storage: unsafe { MaybeUninit::uninit().assume_init() }, len: ChainLength::ZERO }
1060    }
1061}
1062
1063impl<T> FromIterator<T> for Chained<T> {
1064    /// # Panics
1065    ///
1066    /// if the iterator can yield more than MAX_DESCRIPTOR_CHAIN elements.
1067    fn from_iter<I: IntoIterator<Item = T>>(elements: I) -> Self {
1068        let mut result = Self::empty();
1069        let mut len = 0u8;
1070        for (idx, e) in elements.into_iter().enumerate() {
1071            result.storage[idx] = MaybeUninit::new(e);
1072            len += 1;
1073        }
1074        // `len` can not be larger than `MAX_DESCRIPTOR_CHAIN`, otherwise we can't
1075        // get here due to the bound checks on `result.storage`.
1076        result.len = ChainLength::try_from(len).unwrap();
1077        result
1078    }
1079}
1080
1081impl<T> IntoIterator for Chained<T> {
1082    type Item = T;
1083    type IntoIter = ChainedIter<T>;
1084
1085    fn into_iter(mut self) -> Self::IntoIter {
1086        let len = self.len;
1087        self.len = ChainLength::ZERO;
1088        // Safety: we have reset the length to zero, it is now safe to move out
1089        // the values and set them to be uninitialized. The `assume_init` is
1090        // safe because the type we are claiming to have initialized here is a
1091        // bunch of `MaybeUninit`s, which do not require initialization.
1092        // TODO(https://fxbug.dev/42160423): use MaybeUninit::uninit_array once it
1093        // is stablized.
1094        #[allow(clippy::uninit_assumed_init)]
1095        let storage =
1096            std::mem::replace(&mut self.storage, unsafe { MaybeUninit::uninit().assume_init() });
1097        ChainedIter { storage, len, consumed: 0 }
1098    }
1099}
1100
1101struct ChainedIter<T> {
1102    storage: [MaybeUninit<T>; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1103    len: ChainLength,
1104    consumed: u8,
1105}
1106
1107impl<T> Iterator for ChainedIter<T> {
1108    type Item = T;
1109
1110    fn next(&mut self) -> Option<Self::Item> {
1111        if self.consumed < self.len.get() {
1112            // Safety: it is safe now to replace that slot with an uninitialized
1113            // value because we will advance consumed by 1.
1114            let value = unsafe {
1115                std::mem::replace(
1116                    &mut self.storage[usize::from(self.consumed)],
1117                    MaybeUninit::uninit(),
1118                )
1119                .assume_init()
1120            };
1121            self.consumed += 1;
1122            Some(value)
1123        } else {
1124            None
1125        }
1126    }
1127
1128    fn size_hint(&self) -> (usize, Option<usize>) {
1129        let len = usize::from(self.len.get() - self.consumed);
1130        (len, Some(len))
1131    }
1132}
1133
1134impl<T> ExactSizeIterator for ChainedIter<T> {}
1135
1136impl<T> Drop for ChainedIter<T> {
1137    fn drop(&mut self) {
1138        // Safety: `self.storage[self.consumed..self.len]` is initialized.
1139        unsafe {
1140            std::ptr::drop_in_place(std::mem::transmute::<_, &mut [T]>(
1141                &mut self.storage[self.consumed.into()..self.len.into()],
1142            ));
1143        }
1144    }
1145}
1146
1147/// Guards the allocated descriptors; they will be freed when dropped.
1148pub(in crate::session) struct AllocGuard<K: AllocKind> {
1149    descs: Chained<DescId<K>>,
1150    pool: Arc<Pool>,
1151}
1152
1153impl<K: AllocKind> Debug for AllocGuard<K> {
1154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1155        let Self { descs, pool: _ } = self;
1156        f.debug_struct("AllocGuard").field("descs", descs).finish()
1157    }
1158}
1159
1160impl<K: AllocKind> AllocGuard<K> {
1161    fn new(descs: Chained<DescId<K>>, pool: Arc<Pool>) -> Self {
1162        Self { descs, pool }
1163    }
1164
1165    /// Iterates over references to the descriptors.
1166    fn descriptors(&self) -> impl Iterator<Item = DescRef<'_, K>> + '_ {
1167        self.descs.iter().map(move |desc| self.pool.descriptors.borrow(desc))
1168    }
1169
1170    /// Iterates over mutable references to the descriptors.
1171    fn descriptors_mut(&mut self) -> impl Iterator<Item = DescRefMut<'_, K>> + '_ {
1172        let descriptors = &self.pool.descriptors;
1173        self.descs.iter_mut().map(move |desc| descriptors.borrow_mut(desc))
1174    }
1175
1176    /// Gets a reference to the head descriptor.
1177    fn descriptor(&self) -> DescRef<'_, K> {
1178        self.descriptors().next().expect("descriptors must not be empty")
1179    }
1180
1181    /// Gets a mutable reference to the head descriptor.
1182    fn descriptor_mut(&mut self) -> DescRefMut<'_, K> {
1183        self.descriptors_mut().next().expect("descriptors must not be empty")
1184    }
1185}
1186
1187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1188struct DescriptorLayout {
1189    chain_length: ChainLength,
1190    head_length: u16,
1191    data_length: u32,
1192    tail_length: u16,
1193}
1194
1195impl AllocGuard<Tx> {
1196    /// Calculates the layout for each descriptor in this allocation chain.
1197    ///
1198    /// The layouts are calculated to satisfy the requested `target_len`, while
1199    /// ensuring the session's `min_tx_head` and `min_tx_tail` requirements are
1200    /// met.
1201    ///
1202    /// Returns `Err(Error::TxLength)` if the requirements cannot be met (e.g. if the
1203    /// required tail padding overflows `u16`).
1204    fn calculate_descriptor_layouts(&self, target_len: usize) -> Result<Chained<DescriptorLayout>> {
1205        let len = self.len();
1206        let BufferLayout { min_tx_head, min_tx_tail, length: buffer_length, .. } =
1207            self.pool.buffer_layout;
1208
1209        let mut remaining_target = target_len;
1210        (0..len)
1211            .rev()
1212            .map(|clen| {
1213                let chain_length = ChainLength::try_from(clen).unwrap();
1214                let head_length = if clen + 1 == len { min_tx_head } else { 0 };
1215                let mut tail_length = if clen == 0 { min_tx_tail } else { 0 };
1216
1217                // head_length and tail_length. The check was done when the config
1218                // for pool was created, so the subtraction won't overflow.
1219                let available_bytes = u32::try_from(
1220                    buffer_length - usize::from(head_length) - usize::from(tail_length),
1221                )
1222                .unwrap();
1223
1224                let data_length = match u32::try_from(remaining_target) {
1225                    Ok(target) => {
1226                        if target < available_bytes {
1227                            // The target bytes are less than what is available,
1228                            // we need to put the excess in the tail so that the
1229                            // user cannot write more than they requested (or padded).
1230                            let excess = available_bytes - target;
1231                            tail_length = u16::try_from(excess)
1232                                .ok_checked::<TryFromIntError>()
1233                                .and_then(|tail_adjustment| {
1234                                    tail_length.checked_add(tail_adjustment)
1235                                })
1236                                .ok_or(Error::TxLength)?;
1237                        }
1238                        target.min(available_bytes)
1239                    }
1240                    Err(TryFromIntError { .. }) => available_bytes,
1241                };
1242
1243                let data_length_usize =
1244                    usize::try_from(data_length).expect("u32 must fit in a usize");
1245                remaining_target = remaining_target.saturating_sub(data_length_usize);
1246
1247                Ok::<_, Error>(DescriptorLayout {
1248                    chain_length,
1249                    head_length,
1250                    data_length,
1251                    tail_length,
1252                })
1253            })
1254            .collect()
1255    }
1256
1257    /// Initializes descriptors of a tx allocation.
1258    ///
1259    /// We choose to enforce and satisfy the `min_tx_data` layout requirement
1260    /// (imposed by the device/driver) immediately during buffer allocation and
1261    /// initialization here.
1262    ///
1263    /// Consequently, the allocated buffer's capacity (`target_len`) may be
1264    /// larger than the `requested_bytes` if `requested_bytes` is smaller than
1265    /// `min_tx_data`.
1266    ///
1267    /// While this means we might spend CPU cycles zero-padding buffers that are
1268    /// subsequently dropped without being sent (a rare occurrence in typical
1269    /// usage), this guarantees that buffer is always suitable for sending. This
1270    /// also makes the transmit path (`Session::send`) infallible.
1271    fn init(&mut self, requested_bytes: usize) -> Result<()> {
1272        let min_tx_data = self.pool.buffer_layout.min_tx_data;
1273        let target_len = requested_bytes.max(usize::from(min_tx_data));
1274        let layouts = self.calculate_descriptor_layouts(target_len)?;
1275
1276        let mut remaining_requested = requested_bytes;
1277
1278        for (desc_id, DescriptorLayout { chain_length, head_length, data_length, tail_length }) in
1279            self.descs.iter_mut().zip(layouts)
1280        {
1281            // Initialize the descriptor.
1282            {
1283                let mut descriptor = self.pool.descriptors.borrow_mut(desc_id);
1284                descriptor.initialize(chain_length, head_length, data_length, tail_length);
1285            }
1286
1287            let data_length_usize = usize::try_from(data_length).expect("u32 must fit in a usize");
1288            let requested_in_part = std::cmp::min(remaining_requested, data_length_usize);
1289            let pad_in_part = data_length_usize - requested_in_part;
1290
1291            // Zero-pad any excess capacity in this buffer part that was allocated
1292            // to satisfy the `min_tx_data` layout requirement but not requested by
1293            // the caller.
1294            //
1295            // We decided to pad the buffer on initialization because the lazy commit
1296            // model can only avoid padding for the following 2 cases:
1297            // 1) User only allocates but never sends.
1298            // 2) User writes past their requested size and meets the min_tx_data
1299            //    requirement.
1300            // Both should be uncommon, and in case 2) we can fix the client by
1301            // requesting a larger size to avoid padding.
1302            if pad_in_part > 0 {
1303                let slice = self.pool.get_slice_mut(desc_id);
1304                slice[requested_in_part..requested_in_part + pad_in_part].fill(0);
1305            }
1306
1307            remaining_requested -= requested_in_part;
1308        }
1309        Ok(())
1310    }
1311}
1312
1313impl<K: AllocKind> Drop for AllocGuard<K> {
1314    fn drop(&mut self) {
1315        if self.is_empty() {
1316            return;
1317        }
1318        K::free(private::Allocation(self));
1319    }
1320}
1321
1322impl<K: AllocKind> Deref for AllocGuard<K> {
1323    type Target = [DescId<K>];
1324
1325    fn deref(&self) -> &Self::Target {
1326        self.descs.deref()
1327    }
1328}
1329
1330impl<K: AllocKind> From<AllocGuard<K>> for Buffer<K> {
1331    fn from(alloc: AllocGuard<K>) -> Self {
1332        Self { alloc }
1333    }
1334}
1335
1336impl<T, K: AllocKind> Read for BufferIO<T, K>
1337where
1338    T: AsRef<[u8]>,
1339{
1340    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1341        let read_len = self.read_at(self.pos, buf);
1342        self.pos += read_len;
1343        Ok(read_len)
1344    }
1345}
1346
1347impl<T> Write for BufferIO<T, Tx>
1348where
1349    T: AsMut<[u8]>,
1350{
1351    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1352        let write_len = self.write_at(self.pos, buf);
1353        self.pos += write_len;
1354        Ok(write_len)
1355    }
1356
1357    fn flush(&mut self) -> std::io::Result<()> {
1358        Ok(())
1359    }
1360}
1361
1362impl<T, K: AllocKind> Seek for BufferIO<T, K> {
1363    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
1364        let pos = match pos {
1365            SeekFrom::Start(offset) => offset,
1366            SeekFrom::End(offset) => {
1367                let end = i64::try_from(self.len).unwrap();
1368                u64::try_from(end.wrapping_add(offset)).unwrap()
1369            }
1370            SeekFrom::Current(offset) => {
1371                let current = i64::try_from(self.pos).map_err(|TryFromIntError { .. }| {
1372                    std::io::Error::from(std::io::ErrorKind::InvalidInput)
1373                })?;
1374                u64::try_from(current.wrapping_add(offset)).unwrap()
1375            }
1376        };
1377        self.pos = usize::try_from(pos).map_err(|TryFromIntError { .. }| {
1378            std::io::Error::from(std::io::ErrorKind::InvalidInput)
1379        })?;
1380        Ok(pos)
1381    }
1382}
1383
1384/// A pending tx allocation request.
1385struct TxAllocReq {
1386    sender: Sender<AllocGuard<Tx>>,
1387    size: ChainLength,
1388}
1389
1390impl TxAllocReq {
1391    fn new(size: ChainLength) -> (Self, Receiver<AllocGuard<Tx>>) {
1392        let (sender, receiver) = channel();
1393        (TxAllocReq { sender, size }, receiver)
1394    }
1395
1396    /// Fulfills the pending request with an `AllocGuard`.
1397    ///
1398    /// If the request is already closed, the guard is simply dropped and
1399    /// returned to the queue.
1400    ///
1401    /// `fulfill` must *not* be called when the `guard`'s pool is holding the tx
1402    /// lock, since we may deadlock/panic upon the double tx lock acquisition.
1403    fn fulfill(self, guard: AllocGuard<Tx>) {
1404        let Self { sender, size: _ } = self;
1405        match sender.send(guard) {
1406            Ok(()) => (),
1407            Err(guard) => {
1408                // It's ok to just drop the guard here, it'll be returned to the
1409                // pool.
1410                drop(guard);
1411            }
1412        }
1413    }
1414}
1415
1416/// A module for sealed traits so that the user of this crate can not implement
1417/// [`AllocKind`] for anything than [`Rx`] and [`Tx`].
1418mod private {
1419    use super::{AllocKind, Rx, Tx};
1420    pub trait Sealed: 'static + Sized {}
1421    impl Sealed for Rx {}
1422    impl Sealed for Tx {}
1423
1424    // We can't leak a private type in a public trait, create an opaque private
1425    // new type for &mut super::AllocGuard so that we can mention it in the
1426    // AllocKind trait.
1427    pub struct Allocation<'a, K: AllocKind>(pub(super) &'a mut super::AllocGuard<K>);
1428}
1429
1430/// An allocation can have two kinds, this trait provides a way to project a
1431/// type ([`Rx`] or [`Tx`]) into a value.
1432pub trait AllocKind: private::Sealed {
1433    /// The reflected value of Self.
1434    const REFL: AllocKindRefl;
1435
1436    /// frees an allocation of the given kind.
1437    fn free(alloc: private::Allocation<'_, Self>);
1438}
1439
1440/// A tag to related types for Tx allocations.
1441pub enum Tx {}
1442/// A tag to related types for Rx allocations.
1443pub enum Rx {}
1444
1445/// The reflected value that allows inspection on an [`AllocKind`] type.
1446pub enum AllocKindRefl {
1447    Tx,
1448    Rx,
1449}
1450
1451impl AllocKindRefl {
1452    pub(in crate::session) fn as_str(&self) -> &'static str {
1453        match self {
1454            AllocKindRefl::Tx => "Tx",
1455            AllocKindRefl::Rx => "Rx",
1456        }
1457    }
1458}
1459
1460impl AllocKind for Tx {
1461    const REFL: AllocKindRefl = AllocKindRefl::Tx;
1462
1463    fn free(alloc: private::Allocation<'_, Self>) {
1464        let private::Allocation(AllocGuard { pool, descs }) = alloc;
1465        pool.free_tx(std::mem::replace(descs, Chained::empty()));
1466    }
1467}
1468
1469impl AllocKind for Rx {
1470    const REFL: AllocKindRefl = AllocKindRefl::Rx;
1471
1472    fn free(alloc: private::Allocation<'_, Self>) {
1473        let private::Allocation(AllocGuard { pool, descs }) = alloc;
1474        pool.free_rx(std::mem::replace(descs, Chained::empty()));
1475        pool.rx_leases.rx_complete();
1476    }
1477}
1478
1479/// An extracted struct containing state pertaining to watching rx leases.
1480pub(in crate::session) struct RxLeaseHandlingState {
1481    can_watch_rx_leases: AtomicBool,
1482    /// Keeps a rolling counter of received rx frames MINUS the target frame
1483    /// number of the current outstanding lease.
1484    ///
1485    /// When no leases are pending (via [`RxLeaseWatcher::wait_until`]),
1486    /// then this matches exactly the number of received frames.
1487    ///
1488    /// Otherwise, the lease is currently waiting for remaining `u64::MAX -
1489    /// rx_Frame_counter` frames. The logic depends on `AtomicU64` wrapping
1490    /// around as part of completing rx buffers.
1491    rx_frame_counter: AtomicU64,
1492    rx_lease_waker: AtomicWaker,
1493}
1494
1495impl RxLeaseHandlingState {
1496    fn new_with_flags(flags: netdev::SessionFlags) -> Self {
1497        Self::new_with_enabled(flags.contains(netdev::SessionFlags::RECEIVE_RX_POWER_LEASES))
1498    }
1499
1500    fn new_with_enabled(enabled: bool) -> Self {
1501        Self {
1502            can_watch_rx_leases: AtomicBool::new(enabled),
1503            rx_frame_counter: AtomicU64::new(0),
1504            rx_lease_waker: AtomicWaker::new(),
1505        }
1506    }
1507
1508    /// Increments the total receive frame counter and possibly wakes up a
1509    /// waiting lease yielder.
1510    fn rx_complete(&self) {
1511        let Self { can_watch_rx_leases: _, rx_frame_counter, rx_lease_waker } = self;
1512        let prev = rx_frame_counter.fetch_add(1, atomic::Ordering::SeqCst);
1513
1514        // See wait_until for details. We need to hit a waker whenever our add
1515        // wrapped the u64 back around to 0.
1516        if prev == u64::MAX {
1517            rx_lease_waker.wake();
1518        }
1519    }
1520}
1521
1522/// A trait allowing [`RxLeaseWatcher`] to be agnostic over how to get an
1523/// [`RxLeaseHandlingState`].
1524pub(in crate::session) trait RxLeaseHandlingStateContainer {
1525    fn lease_handling_state(&self) -> &RxLeaseHandlingState;
1526}
1527
1528impl<T: Borrow<RxLeaseHandlingState>> RxLeaseHandlingStateContainer for T {
1529    fn lease_handling_state(&self) -> &RxLeaseHandlingState {
1530        self.borrow()
1531    }
1532}
1533
1534impl RxLeaseHandlingStateContainer for Arc<Pool> {
1535    fn lease_handling_state(&self) -> &RxLeaseHandlingState {
1536        &self.rx_leases
1537    }
1538}
1539
1540/// A type safe-wrapper around a single lease watcher per `Pool`.
1541pub(in crate::session) struct RxLeaseWatcher<T> {
1542    state: T,
1543}
1544
1545impl<T: RxLeaseHandlingStateContainer> RxLeaseWatcher<T> {
1546    /// Creates a new lease watcher.
1547    ///
1548    /// # Panics
1549    ///
1550    /// Panics if an [`RxLeaseWatcher`] has already been created for the given
1551    /// pool or the pool was not configured for it.
1552    pub(in crate::session) fn new(state: T) -> Self {
1553        assert!(
1554            state.lease_handling_state().can_watch_rx_leases.swap(false, atomic::Ordering::SeqCst),
1555            "can't watch rx leases"
1556        );
1557        Self { state }
1558    }
1559
1560    /// Called by sessions to wait until `hold_until_frame` is fulfilled to
1561    /// yield leases out.
1562    ///
1563    /// Blocks until `hold_until_frame`-th rx buffer has been released.
1564    ///
1565    /// Note that this method takes `&mut self` because only one
1566    /// [`RxLeaseWatcher`] may be created by lease handling state, and exclusive
1567    /// access to it is required to watch lease completion.
1568    pub(in crate::session) async fn wait_until(&mut self, hold_until_frame: u64) {
1569        // A note about wrap-arounds.
1570        //
1571        // We're assuming the frame counter will never wrap around for
1572        // correctness here. This should be fine, even assuming a packet
1573        // rate of 1 million pps it'd take almost 600k years for this counter
1574        // to wrap around:
1575        // - 2^64 / 1e6 / 60 / 60 / 24 / 365 ~ 584e3.
1576
1577        let RxLeaseHandlingState { can_watch_rx_leases: _, rx_frame_counter, rx_lease_waker } =
1578            self.state.lease_handling_state();
1579
1580        let prev = rx_frame_counter.fetch_sub(hold_until_frame, atomic::Ordering::SeqCst);
1581        // After having subtracted the waiting value we *must always restore the
1582        // value* on return, even if the future is not polled to completion.
1583        let _guard = scopeguard::guard((), |()| {
1584            let _: u64 = rx_frame_counter.fetch_add(hold_until_frame, atomic::Ordering::SeqCst);
1585        });
1586
1587        // Lease is ready to be fulfilled.
1588        if prev >= hold_until_frame {
1589            return;
1590        }
1591        // Threshold is a wrapped around subtraction. So now we must wait
1592        // until the read value from the atomic is LESS THAN the threshold.
1593        let threshold = prev.wrapping_sub(hold_until_frame);
1594        futures::future::poll_fn(|cx| {
1595            let v = rx_frame_counter.load(atomic::Ordering::SeqCst);
1596            if v < threshold {
1597                return Poll::Ready(());
1598            }
1599            rx_lease_waker.register(cx.waker());
1600            let v = rx_frame_counter.load(atomic::Ordering::SeqCst);
1601            if v < threshold {
1602                return Poll::Ready(());
1603            }
1604            Poll::Pending
1605        })
1606        .await;
1607    }
1608}
1609
1610#[cfg(test)]
1611mod tests {
1612
1613    use super::*;
1614
1615    use assert_matches::assert_matches;
1616    use fuchsia_async as fasync;
1617    use futures::future::FutureExt;
1618    use test_case::test_case;
1619
1620    use std::collections::HashSet;
1621    use std::num::{NonZeroU16, NonZeroU64, NonZeroUsize};
1622    use std::pin::pin;
1623    use std::task::Poll;
1624
1625    use crate::session::tx::TxVmoConfig;
1626
1627    const DEFAULT_MIN_TX_BUFFER_HEAD: u16 = 4;
1628    const DEFAULT_MIN_TX_BUFFER_TAIL: u16 = 8;
1629    // Safety: These are safe because none of the values are zero.
1630    const DEFAULT_BUFFER_LENGTH: NonZeroUsize = NonZeroUsize::new(64).unwrap();
1631    const DEFAULT_TX_BUFFERS: NonZeroU16 = NonZeroU16::new(8).unwrap();
1632    const DEFAULT_RX_BUFFERS: NonZeroU16 = NonZeroU16::new(8).unwrap();
1633    const MAX_BUFFER_BYTES: usize = DEFAULT_BUFFER_LENGTH.get()
1634        * netdev::MAX_DESCRIPTOR_CHAIN as usize
1635        - DEFAULT_MIN_TX_BUFFER_HEAD as usize
1636        - DEFAULT_MIN_TX_BUFFER_TAIL as usize;
1637
1638    const SENTINEL_BYTE: u8 = 0xab;
1639    const WRITE_BYTE: u8 = 1;
1640    const PAD_BYTE: u8 = 0;
1641
1642    fn default_config() -> Config {
1643        Config {
1644            buffer_stride: NonZeroU64::new(DEFAULT_BUFFER_LENGTH.get() as u64).unwrap(),
1645            num_rx_buffers: DEFAULT_RX_BUFFERS,
1646            tx_vmos: vec![TxVmoConfig {
1647                vmo_id: DEFAULT_VMO_ID,
1648                num_buffers: DEFAULT_TX_BUFFERS.get(),
1649            }],
1650            options: netdev::SessionFlags::empty(),
1651            buffer_layout: BufferLayout {
1652                length: DEFAULT_BUFFER_LENGTH.get(),
1653                min_tx_head: DEFAULT_MIN_TX_BUFFER_HEAD,
1654                min_tx_tail: DEFAULT_MIN_TX_BUFFER_TAIL,
1655                min_tx_data: 0,
1656            },
1657            buffer_usage_sample_interval: std::time::Duration::from_secs(1),
1658        }
1659    }
1660
1661    impl Pool {
1662        fn new_test_pool(config: Config) -> (Arc<Self>, zx::Vmo, Vec<zx::Vmo>) {
1663            let CreatedPool { pool, descriptors_vmo, data_vmos } =
1664                Pool::new(config).expect("failed to create pool");
1665            (pool, descriptors_vmo, data_vmos)
1666        }
1667
1668        fn new_test_default() -> Arc<Self> {
1669            let (pool, _descriptors, _data) = Pool::new_test_pool(default_config());
1670            pool
1671        }
1672
1673        fn tx_alloc_state_lock(&self) -> fuchsia_sync::MutexGuard<'_, TxAllocState> {
1674            self.tx_alloc_state.lock()
1675        }
1676
1677        async fn alloc_tx_checked(self: &Arc<Self>, n: u8) -> AllocGuard<Tx> {
1678            self.alloc_tx(ChainLength::try_from(n).expect("failed to convert to chain length"))
1679                .await
1680        }
1681
1682        fn alloc_tx_now_or_never(self: &Arc<Self>, n: u8) -> Option<AllocGuard<Tx>> {
1683            self.alloc_tx_checked(n).now_or_never()
1684        }
1685
1686        fn alloc_tx_all(self: &Arc<Self>, n: u8) -> Vec<AllocGuard<Tx>> {
1687            std::iter::from_fn(|| self.alloc_tx_now_or_never(n)).collect()
1688        }
1689
1690        fn alloc_tx_buffer_now_or_never(self: &Arc<Self>, num_bytes: usize) -> Option<Buffer<Tx>> {
1691            self.alloc_tx_buffer(num_bytes)
1692                .now_or_never()
1693                .transpose()
1694                .expect("invalid arguments for alloc_tx_buffer")
1695        }
1696
1697        fn set_min_tx_buffer_length(self: &mut Arc<Self>, length: usize) {
1698            Arc::get_mut(self).unwrap().buffer_layout.min_tx_data = length;
1699        }
1700
1701        fn fill_sentinel_bytes(&mut self) {
1702            // Safety: We have mut reference to Pool, so we get to modify the
1703            // VMO pointed by self.base.
1704            let bytes = *self.vmo_offsets.last().unwrap();
1705            unsafe { std::ptr::write_bytes(self.base.as_ptr(), SENTINEL_BYTE, bytes) };
1706        }
1707    }
1708
1709    impl Buffer<Tx> {
1710        // Write a byte at offset, the result buffer should be pad_size long, with
1711        // 0..offset being the SENTINEL_BYTE, offset being the WRITE_BYTE and the
1712        // rest being PAD_BYTE.
1713        fn check_write_and_pad(&mut self, offset: usize, pad_size: usize) {
1714            {
1715                let mut io = self.io_mut();
1716                assert_eq!(io.write_at(offset, &[WRITE_BYTE][..]), 1);
1717            }
1718            assert_eq!(self.len(), pad_size);
1719            // An arbitrary value that is not SENTINAL/WRITE/PAD_BYTE so that
1720            // we can make sure the write really happened.
1721            const INIT_BYTE: u8 = 42;
1722            let mut read_buf = vec![INIT_BYTE; pad_size];
1723            assert_eq!(self.io().read_at(0, &mut read_buf[..]), read_buf.len());
1724            for (idx, byte) in read_buf.iter().enumerate() {
1725                if idx < offset {
1726                    assert_eq!(*byte, SENTINEL_BYTE);
1727                } else if idx == offset {
1728                    assert_eq!(*byte, WRITE_BYTE);
1729                } else {
1730                    assert_eq!(*byte, PAD_BYTE);
1731                }
1732            }
1733        }
1734    }
1735
1736    impl<K, I, T> PartialEq<T> for Chained<DescId<K>>
1737    where
1738        K: AllocKind,
1739        I: ExactSizeIterator<Item = u16>,
1740        T: Copy + IntoIterator<IntoIter = I>,
1741    {
1742        fn eq(&self, other: &T) -> bool {
1743            let iter = other.into_iter();
1744            if usize::from(self.len) != iter.len() {
1745                return false;
1746            }
1747            self.iter().zip(iter).all(|(l, r)| l.get() == r)
1748        }
1749    }
1750
1751    impl Debug for TxAllocReq {
1752        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1753            let TxAllocReq { sender: _, size } = self;
1754            f.debug_struct("TxAllocReq").field("size", &size).finish_non_exhaustive()
1755        }
1756    }
1757
1758    #[test]
1759    fn alloc_tx_distinct() {
1760        let pool = Pool::new_test_default();
1761        let allocated = pool.alloc_tx_all(1);
1762        assert_eq!(allocated.len(), DEFAULT_TX_BUFFERS.get().into());
1763        let distinct = allocated
1764            .iter()
1765            .map(|alloc| {
1766                assert_eq!(alloc.descs.len(), 1);
1767                alloc.descs[0].get()
1768            })
1769            .collect::<HashSet<u16>>();
1770        assert_eq!(allocated.len(), distinct.len());
1771    }
1772
1773    #[test]
1774    fn alloc_tx_free_len() {
1775        let pool = Pool::new_test_default();
1776        {
1777            let allocated = pool.alloc_tx_all(2);
1778            assert_eq!(
1779                allocated.iter().fold(0, |acc, a| { acc + a.descs.len() }),
1780                DEFAULT_TX_BUFFERS.get().into()
1781            );
1782            assert_eq!(pool.tx_alloc_state_lock().free_lists[0].free, 0);
1783        }
1784        assert_eq!(pool.tx_alloc_state_lock().free_lists[0].free, DEFAULT_TX_BUFFERS.get());
1785    }
1786
1787    #[test]
1788    fn alloc_tx_chain() {
1789        let pool = Pool::new_test_default();
1790        let allocated = pool.alloc_tx_all(3);
1791        assert_eq!(allocated.len(), usize::from(DEFAULT_TX_BUFFERS.get()) / 3);
1792        assert_matches!(pool.alloc_tx_now_or_never(3), None);
1793        assert_matches!(pool.alloc_tx_now_or_never(2), Some(a) if a.descs.len() == 2);
1794    }
1795
1796    #[test]
1797    fn alloc_tx_many() {
1798        let pool = Pool::new_test_default();
1799        let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1800            - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
1801            - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
1802        let data_len = usize::try_from(data_len).unwrap();
1803        let mut buffers = pool
1804            .alloc_tx_buffers(data_len)
1805            .now_or_never()
1806            .expect("failed to alloc")
1807            .unwrap()
1808            // Collect into a vec so we keep the buffers alive, otherwise they
1809            // are immediately returned to the pool.
1810            .collect::<Result<Vec<_>>>()
1811            .expect("buffer error");
1812        assert_eq!(buffers.len(), DEFAULT_TX_BUFFERS.get().into());
1813
1814        // We have all the buffers, which means allocating more should not
1815        // resolve.
1816        assert!(pool.alloc_tx_buffers(data_len).now_or_never().is_none());
1817
1818        // If we release a single buffer we should be able to retrieve it again.
1819        assert_matches!(buffers.pop(), Some(_));
1820        let mut more_buffers =
1821            pool.alloc_tx_buffers(data_len).now_or_never().expect("failed to alloc").unwrap();
1822        let buffer = assert_matches!(more_buffers.next(), Some(Ok(b)) => b);
1823        assert_matches!(more_buffers.next(), None);
1824        // The iterator is fused, so None is yielded even after dropping the
1825        // buffer.
1826        drop(buffer);
1827        assert_matches!(more_buffers.next(), None);
1828    }
1829
1830    #[test]
1831    fn alloc_tx_after_free() {
1832        let pool = Pool::new_test_default();
1833        let mut allocated = pool.alloc_tx_all(1);
1834        assert_matches!(pool.alloc_tx_now_or_never(2), None);
1835        {
1836            let _drained = allocated.drain(..2);
1837        }
1838        assert_matches!(pool.alloc_tx_now_or_never(2), Some(a) if a.descs.len() == 2);
1839    }
1840
1841    #[test]
1842    fn blocking_alloc_tx() {
1843        let mut executor = fasync::TestExecutor::new();
1844        let pool = Pool::new_test_default();
1845        let mut allocated = pool.alloc_tx_all(1);
1846        let alloc_fut = pool.alloc_tx_checked(1);
1847        let mut alloc_fut = pin!(alloc_fut);
1848        // The allocation should block.
1849        assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1850        // And the allocation request should be queued.
1851        assert!(!pool.tx_alloc_state_lock().requests.is_empty());
1852        let freed = allocated
1853            .pop()
1854            .expect("no fulfulled allocations")
1855            .iter()
1856            .map(|x| x.get())
1857            .collect::<Chained<_>>();
1858        let same_as_freed =
1859            |descs: &Chained<DescId<Tx>>| descs.iter().map(|x| x.get()).eq(freed.iter().copied());
1860        // Now the task should be able to continue.
1861        assert_matches!(
1862            &executor.run_until_stalled(&mut alloc_fut),
1863            Poll::Ready(AllocGuard{ descs, pool: _ }) if same_as_freed(descs)
1864        );
1865        // And the queued request should now be removed.
1866        assert!(pool.tx_alloc_state_lock().requests.is_empty());
1867    }
1868
1869    #[test]
1870    fn blocking_alloc_tx_cancel_before_free() {
1871        let mut executor = fasync::TestExecutor::new();
1872        let pool = Pool::new_test_default();
1873        let mut allocated = pool.alloc_tx_all(1);
1874        {
1875            let alloc_fut = pool.alloc_tx_checked(1);
1876            let mut alloc_fut = pin!(alloc_fut);
1877            assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1878            assert_matches!(
1879                pool.tx_alloc_state_lock().requests.as_slices(),
1880                (&[ref req1, ref req2], &[]) if req1.size.get() == 1 && req2.size.get() == 1
1881            );
1882        }
1883        assert_matches!(
1884            allocated.pop(),
1885            Some(AllocGuard { ref descs, pool: ref p })
1886                if descs == &[DEFAULT_TX_BUFFERS.get() - 1] && Arc::ptr_eq(p, &pool)
1887        );
1888        let state = pool.tx_alloc_state_lock();
1889        assert_eq!(state.free_lists[0].free, 1);
1890        assert!(state.requests.is_empty());
1891    }
1892
1893    #[test]
1894    fn blocking_alloc_tx_cancel_after_free() {
1895        let mut executor = fasync::TestExecutor::new();
1896        let pool = Pool::new_test_default();
1897        let mut allocated = pool.alloc_tx_all(1);
1898        {
1899            let alloc_fut = pool.alloc_tx_checked(1);
1900            let mut alloc_fut = pin!(alloc_fut);
1901            assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1902            assert_matches!(
1903                pool.tx_alloc_state_lock().requests.as_slices(),
1904                (&[ref req1, ref req2], &[]) if req1.size.get() == 1 && req2.size.get() == 1
1905            );
1906            assert_matches!(
1907                allocated.pop(),
1908                Some(AllocGuard { ref descs, pool: ref p })
1909                    if descs == &[DEFAULT_TX_BUFFERS.get() - 1] && Arc::ptr_eq(p, &pool)
1910            );
1911        }
1912        let state = pool.tx_alloc_state_lock();
1913        assert_eq!(state.free_lists[0].free, 1);
1914        assert!(state.requests.is_empty());
1915    }
1916
1917    #[test]
1918    fn multiple_blocking_alloc_tx_fulfill_order() {
1919        const TASKS_TOTAL: usize = 3;
1920        let mut executor = fasync::TestExecutor::new();
1921        let pool = Pool::new_test_default();
1922        let mut allocated = pool.alloc_tx_all(1);
1923        let mut alloc_futs = (1..=TASKS_TOTAL)
1924            .rev()
1925            .map(|x| {
1926                let pool = pool.clone();
1927                (x, Box::pin(async move { pool.alloc_tx_checked(x.try_into().unwrap()).await }))
1928            })
1929            .collect::<Vec<_>>();
1930
1931        for (idx, (req_size, task)) in alloc_futs.iter_mut().enumerate() {
1932            assert_matches!(executor.run_until_stalled(task), Poll::Pending);
1933            // assert that the tasks are sorted decreasing on the requested size.
1934            assert_eq!(idx + *req_size, TASKS_TOTAL);
1935        }
1936        {
1937            let state = pool.tx_alloc_state_lock();
1938            // The first pending request was introduced by `alloc_tx_all`.
1939            assert_eq!(state.requests.len(), TASKS_TOTAL + 1);
1940            let mut requests = state.requests.iter();
1941            // It should already be cancelled because the requesting future is
1942            // already dropped.
1943            assert!(requests.next().unwrap().sender.is_canceled());
1944            // The rest of the requests must not be cancelled.
1945            assert!(requests.all(|req| !req.sender.is_canceled()))
1946        }
1947
1948        let mut to_free = Vec::new();
1949        let mut freed = 0;
1950        for free_size in (1..=TASKS_TOTAL).rev() {
1951            let (_req_size, mut task) = alloc_futs.remove(0);
1952            for _ in 1..free_size {
1953                freed += 1;
1954                assert_matches!(
1955                    allocated.pop(),
1956                    Some(AllocGuard { ref descs, pool: ref p })
1957                        if descs == &[DEFAULT_TX_BUFFERS.get() - freed] && Arc::ptr_eq(p, &pool)
1958                );
1959                assert_matches!(executor.run_until_stalled(&mut task), Poll::Pending);
1960            }
1961            freed += 1;
1962            assert_matches!(
1963                allocated.pop(),
1964                Some(AllocGuard { ref descs, pool: ref p })
1965                    if descs == &[DEFAULT_TX_BUFFERS.get() - freed] && Arc::ptr_eq(p, &pool)
1966            );
1967            match executor.run_until_stalled(&mut task) {
1968                Poll::Ready(alloc) => {
1969                    assert_eq!(alloc.len(), free_size);
1970                    // Don't return the allocation to the pool now.
1971                    to_free.push(alloc);
1972                }
1973                Poll::Pending => panic!("The request should be fulfilled"),
1974            }
1975            // The rest of requests can not be fulfilled.
1976            for (_req_size, task) in alloc_futs.iter_mut() {
1977                assert_matches!(executor.run_until_stalled(task), Poll::Pending);
1978            }
1979        }
1980        assert!(pool.tx_alloc_state_lock().requests.is_empty());
1981    }
1982
1983    #[test]
1984    fn singleton_tx_layout() {
1985        let pool = Pool::new_test_default();
1986        let buffers = std::iter::from_fn(|| {
1987            let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1988                - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
1989                - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
1990            pool.alloc_tx_buffer_now_or_never(usize::try_from(data_len).unwrap()).map(|buffer| {
1991                assert_eq!(buffer.alloc.descriptors().count(), 1);
1992                let offset = u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1993                    * u64::from(buffer.alloc[0].get());
1994                {
1995                    let descriptor = buffer.alloc.descriptor();
1996                    assert_matches!(descriptor.chain_length(), Ok(ChainLength::ZERO));
1997                    assert_eq!(descriptor.head_length(), DEFAULT_MIN_TX_BUFFER_HEAD);
1998                    assert_eq!(descriptor.tail_length(), DEFAULT_MIN_TX_BUFFER_TAIL);
1999                    assert_eq!(descriptor.data_length(), data_len);
2000                    assert_eq!(descriptor.offset(), offset);
2001                }
2002
2003                {
2004                    let mut slices = buffer.parts();
2005                    let slice = slices.next().expect("should have one slice");
2006                    assert_matches!(slices.next(), None);
2007                    assert_eq!(slice.len(), usize::try_from(data_len).unwrap());
2008                    assert_eq!(
2009                        slice.as_ptr(),
2010                        pool.base.as_ptr().wrapping_add(
2011                            usize::try_from(offset).unwrap()
2012                                + usize::from(DEFAULT_MIN_TX_BUFFER_HEAD),
2013                        )
2014                    );
2015                }
2016                buffer
2017            })
2018        })
2019        .collect::<Vec<_>>();
2020        assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()));
2021    }
2022
2023    #[test]
2024    fn chained_tx_layout() {
2025        let pool = Pool::new_test_default();
2026        let alloc_len = 4 * DEFAULT_BUFFER_LENGTH.get()
2027            - usize::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2028            - usize::from(DEFAULT_MIN_TX_BUFFER_TAIL);
2029        let buffers = std::iter::from_fn(|| {
2030            pool.alloc_tx_buffer_now_or_never(alloc_len).map(|buffer| {
2031                assert_eq!(buffer.parts().count(), 4);
2032                for (idx, (descriptor, slice)) in
2033                    buffer.alloc.descriptors().zip(buffer.parts()).enumerate()
2034                {
2035                    let chain_length = ChainLength::try_from(buffer.alloc.len() - idx - 1).unwrap();
2036                    let head_length = if idx == 0 { DEFAULT_MIN_TX_BUFFER_HEAD } else { 0 };
2037                    let tail_length = if chain_length == ChainLength::ZERO {
2038                        DEFAULT_MIN_TX_BUFFER_TAIL
2039                    } else {
2040                        0
2041                    };
2042                    let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2043                        - u32::from(head_length)
2044                        - u32::from(tail_length);
2045                    let offset = u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2046                        * u64::from(buffer.alloc[idx].get());
2047                    assert_eq!(descriptor.chain_length().unwrap(), chain_length);
2048                    assert_eq!(descriptor.head_length(), head_length);
2049                    assert_eq!(descriptor.tail_length(), tail_length);
2050                    assert_eq!(descriptor.offset(), offset);
2051                    assert_eq!(descriptor.data_length(), data_len);
2052                    if chain_length != ChainLength::ZERO {
2053                        assert_eq!(descriptor.nxt(), Some(buffer.alloc[idx + 1].get()));
2054                    }
2055
2056                    assert_eq!(slice.len(), usize::try_from(data_len).unwrap());
2057                    assert_eq!(
2058                        slice.as_ptr(),
2059                        pool.base.as_ptr().wrapping_add(
2060                            usize::try_from(offset).unwrap() + usize::from(head_length),
2061                        )
2062                    );
2063                }
2064                buffer
2065            })
2066        })
2067        .collect::<Vec<_>>();
2068        assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()) / 4);
2069    }
2070
2071    #[test]
2072    fn rx_distinct() {
2073        let pool = Pool::new_test_default();
2074        let mut guard = pool.rx_pending.lock();
2075        let descs = &mut guard.storage;
2076        assert_eq!(descs.len(), usize::from(DEFAULT_RX_BUFFERS.get()));
2077        let distinct = descs.iter().map(|desc| desc.get()).collect::<HashSet<u16>>();
2078        assert_eq!(descs.len(), distinct.len());
2079    }
2080
2081    #[test]
2082    fn alloc_rx_layout() {
2083        let pool = Pool::new_test_default();
2084        let mut guard = pool.rx_pending.lock();
2085        let descs = &mut guard.storage;
2086        assert_eq!(descs.len(), usize::from(DEFAULT_RX_BUFFERS.get()));
2087        for desc in descs.iter() {
2088            let descriptor = pool.descriptors.borrow(desc);
2089            let offset =
2090                u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap() * u64::from(desc.get());
2091            assert_matches!(descriptor.chain_length(), Ok(ChainLength::ZERO));
2092            assert_eq!(descriptor.head_length(), 0);
2093            assert_eq!(descriptor.tail_length(), 0);
2094            assert_eq!(descriptor.offset(), offset);
2095            assert_eq!(
2096                descriptor.data_length(),
2097                u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2098            );
2099        }
2100    }
2101
2102    #[test]
2103    fn buffer_read_at_write_at() {
2104        let pool = Pool::new_test_default();
2105        let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2106        let mut buffer =
2107            pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2108        // Because we have to accommodate the space for head and tail, there
2109        // would be 2 parts instead of 1.
2110        assert_eq!(buffer.parts().count(), 2);
2111        assert_eq!(buffer.len(), alloc_bytes);
2112        let write_buf = (0..u8::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()).collect::<Vec<_>>();
2113        assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), write_buf.len());
2114        let mut read_buf = [0xff; DEFAULT_BUFFER_LENGTH.get()];
2115        assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), read_buf.len());
2116        for (idx, byte) in read_buf.iter().enumerate() {
2117            assert_eq!(*byte, write_buf[idx]);
2118        }
2119    }
2120
2121    #[test]
2122    fn buffer_write_at_short() {
2123        let pool = Pool::new_test_default();
2124        let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2125        let mut buffer =
2126            pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2127        assert_eq!(buffer.parts().count(), 2);
2128        assert_eq!(buffer.len(), alloc_bytes);
2129
2130        let write_buf = vec![WRITE_BYTE; alloc_bytes + 10];
2131
2132        // Test short write (writing more than buffer capacity)
2133        assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2134
2135        // Verify short write
2136        let mut read_buf = vec![0; alloc_bytes];
2137        assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2138        for byte in read_buf.iter() {
2139            assert_eq!(*byte, WRITE_BYTE);
2140        }
2141
2142        // Test write with offset past end
2143        assert_eq!(buffer.io_mut().write_at(alloc_bytes + 1, &write_buf[..]), 0);
2144
2145        // Test write with offset inside buffer but src extending past end
2146        let offset = alloc_bytes / 2;
2147        let expected_write = alloc_bytes - offset;
2148        let write_buf = vec![2; alloc_bytes]; // Different byte to distinguish
2149        assert_eq!(buffer.io_mut().write_at(offset, &write_buf[..]), expected_write);
2150
2151        // Verify the write
2152        let mut read_buf = vec![0; alloc_bytes];
2153        assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2154        for (idx, byte) in read_buf.iter().enumerate() {
2155            if idx < offset {
2156                assert_eq!(*byte, WRITE_BYTE);
2157            } else {
2158                assert_eq!(*byte, 2);
2159            }
2160        }
2161    }
2162
2163    #[test]
2164    fn buffer_read_at_short() {
2165        let pool = Pool::new_test_default();
2166        let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2167        let mut buffer =
2168            pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2169        assert_eq!(buffer.parts().count(), 2);
2170        assert_eq!(buffer.len(), alloc_bytes);
2171
2172        let write_buf = vec![WRITE_BYTE; alloc_bytes];
2173        assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2174
2175        // Test short read (reading more than buffer capacity)
2176        let mut read_buf = vec![0xff; alloc_bytes + 10];
2177        assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2178        for (idx, byte) in read_buf.iter().enumerate() {
2179            if idx < alloc_bytes {
2180                assert_eq!(*byte, WRITE_BYTE);
2181            } else {
2182                assert_eq!(*byte, 0xff);
2183            }
2184        }
2185
2186        // Test read with offset past end
2187        assert_eq!(buffer.io().read_at(alloc_bytes + 1, &mut read_buf[..]), 0);
2188
2189        // Test read with offset inside buffer but dst extending past end
2190        let offset = alloc_bytes / 2;
2191        let expected_read = alloc_bytes - offset;
2192        let mut read_buf = vec![0xff; alloc_bytes];
2193        assert_eq!(buffer.io().read_at(offset, &mut read_buf[..]), expected_read);
2194        for (idx, byte) in read_buf.iter().enumerate() {
2195            if idx < expected_read {
2196                assert_eq!(*byte, WRITE_BYTE);
2197            } else {
2198                assert_eq!(*byte, 0xff);
2199            }
2200        }
2201    }
2202
2203    #[test]
2204    fn buffer_read_write_seek() {
2205        let pool = Pool::new_test_default();
2206        let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2207        let mut buffer =
2208            pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2209        // Because we have to accommodate the space for head and tail, there
2210        // would be 2 parts instead of 1.
2211        assert_eq!(buffer.parts().count(), 2);
2212        assert_eq!(buffer.len(), alloc_bytes);
2213        let write_buf = (0..u8::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()).collect::<Vec<_>>();
2214
2215        let mut io = buffer.io_mut();
2216
2217        assert_eq!(io.write(&write_buf[..]).expect("failed to write into buffer"), write_buf.len());
2218        const SEEK_FROM_END: usize = 64;
2219        const READ_LEN: usize = 12;
2220        assert_eq!(
2221            io.seek(SeekFrom::End(-i64::try_from(SEEK_FROM_END).unwrap())).unwrap(),
2222            u64::try_from(io.len - SEEK_FROM_END).unwrap()
2223        );
2224        let mut read_buf = [0xff; READ_LEN];
2225        assert_eq!(io.read(&mut read_buf[..]).expect("failed to read from buffer"), read_buf.len());
2226        assert_eq!(&write_buf[..READ_LEN], &read_buf[..]);
2227    }
2228
2229    #[test_case(32; "single buffer part")]
2230    #[test_case(MAX_BUFFER_BYTES; "multiple buffer parts")]
2231    fn buffer_pad(pad_size: usize) {
2232        let mut pool = Pool::new_test_default();
2233        pool.set_min_tx_buffer_length(pad_size);
2234        for offset in 0..pad_size {
2235            Arc::get_mut(&mut pool)
2236                .expect("there are multiple owners of the underlying VMO")
2237                .fill_sentinel_bytes();
2238            let mut buffer =
2239                pool.alloc_tx_buffer_now_or_never(offset + 1).expect("failed to allocate buffer");
2240            buffer.check_write_and_pad(offset, pad_size);
2241        }
2242    }
2243
2244    #[test]
2245    fn buffer_pad_grow() {
2246        const BUFFER_PARTS: u8 = 3;
2247        let mut pool = Pool::new_test_default();
2248        let pad_size = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2249            * u32::from(BUFFER_PARTS)
2250            - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2251            - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
2252        pool.set_min_tx_buffer_length(pad_size.try_into().unwrap());
2253        for offset in 0..pad_size - u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap() {
2254            Arc::get_mut(&mut pool)
2255                .expect("there are multiple owners of the underlying VMO")
2256                .fill_sentinel_bytes();
2257            let mut alloc =
2258                pool.alloc_tx_now_or_never(BUFFER_PARTS).expect("failed to alloc descriptors");
2259            alloc
2260                .init(usize::try_from(offset).unwrap() + 1)
2261                .expect("head/body/tail sizes are representable with u16/u32/u16");
2262            let mut buffer = Buffer::try_from(alloc).unwrap();
2263            buffer.check_write_and_pad(offset.try_into().unwrap(), pad_size.try_into().unwrap());
2264        }
2265    }
2266
2267    #[test_case(  0; "writes at the beginning")]
2268    #[test_case( 15; "writes in the first part")]
2269    #[test_case( 75; "writes in the second part")]
2270    #[test_case(135; "writes in the third part")]
2271    #[test_case(195; "writes in the last part")]
2272    fn buffer_used(write_offset: usize) {
2273        let pool = Pool::new_test_default();
2274        let mut buffer =
2275            pool.alloc_tx_buffer_now_or_never(MAX_BUFFER_BYTES).expect("failed to allocate buffer");
2276        let expected_caps = (0..netdev::MAX_DESCRIPTOR_CHAIN).map(|i| {
2277            if i == 0 {
2278                DEFAULT_BUFFER_LENGTH.get() - usize::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2279            } else if i < netdev::MAX_DESCRIPTOR_CHAIN - 1 {
2280                DEFAULT_BUFFER_LENGTH.get()
2281            } else {
2282                DEFAULT_BUFFER_LENGTH.get() - usize::from(DEFAULT_MIN_TX_BUFFER_TAIL)
2283            }
2284        });
2285        assert_eq!(buffer.alloc.len(), netdev::MAX_DESCRIPTOR_CHAIN.into());
2286        assert_eq!(buffer.io_mut().write_at(write_offset, &[WRITE_BYTE][..]), 1);
2287        // The accumulator is Some if we haven't found the part where the byte
2288        // was written, None if we've already found it.
2289        assert_eq!(
2290            buffer.parts().zip(expected_caps).fold(
2291                Some(write_offset),
2292                |offset, (slice, expected_cap)| {
2293                    assert_eq!(slice.len(), expected_cap);
2294                    match offset {
2295                        Some(offset) => {
2296                            if offset >= expected_cap {
2297                                Some(offset - slice.len())
2298                            } else {
2299                                assert_eq!(slice[offset], WRITE_BYTE);
2300                                None
2301                            }
2302                        }
2303                        None => None,
2304                    }
2305                }
2306            ),
2307            None
2308        );
2309    }
2310
2311    #[test]
2312    fn allocate_under_device_minimum() {
2313        const MIN_TX_DATA: usize = 32;
2314        const ALLOC_SIZE: usize = 16;
2315        const WRITE_BYTE: u8 = 0xff;
2316        const WRITE_SENTINAL_BYTE: u8 = 0xee;
2317        const READ_SENTINAL_BYTE: u8 = 0xdd;
2318        let mut config = default_config();
2319        config.buffer_layout.min_tx_data = MIN_TX_DATA;
2320        let (pool, _descriptors, _vmo) = Pool::new_test_pool(config);
2321        for mut buffer in Vec::from_iter(std::iter::from_fn({
2322            let pool = pool.clone();
2323            move || pool.alloc_tx_buffer_now_or_never(MIN_TX_DATA)
2324        })) {
2325            assert_eq!(
2326                buffer.io_mut().write_at(0, &[WRITE_SENTINAL_BYTE; MIN_TX_DATA]),
2327                MIN_TX_DATA
2328            );
2329        }
2330        let mut allocated =
2331            pool.alloc_tx_buffer_now_or_never(16).expect("failed to allocate buffer");
2332        assert_eq!(allocated.len(), MIN_TX_DATA);
2333        const WRITE_BUF_SIZE: usize = MIN_TX_DATA + 1;
2334        assert_eq!(allocated.io_mut().write_at(0, &[WRITE_BYTE; WRITE_BUF_SIZE]), MIN_TX_DATA);
2335        assert_eq!(allocated.io_mut().write_at(0, &[WRITE_BYTE; ALLOC_SIZE]), ALLOC_SIZE);
2336        assert_eq!(allocated.len(), MIN_TX_DATA);
2337        const READ_BUF_SIZE: usize = MIN_TX_DATA + 1;
2338        let mut read_buf = [READ_SENTINAL_BYTE; READ_BUF_SIZE];
2339        assert_eq!(allocated.io().read_at(0, &mut read_buf[..]), MIN_TX_DATA);
2340        assert_eq!(allocated.io().read_at(0, &mut read_buf[..MIN_TX_DATA]), MIN_TX_DATA);
2341        assert_eq!(&read_buf[..ALLOC_SIZE], &[WRITE_BYTE; ALLOC_SIZE][..]);
2342        assert_eq!(&read_buf[ALLOC_SIZE..MIN_TX_DATA], &[WRITE_BYTE; ALLOC_SIZE][..]);
2343        assert_eq!(&read_buf[MIN_TX_DATA..], &[READ_SENTINAL_BYTE; 1][..]);
2344    }
2345
2346    #[test]
2347    fn invalid_tx_length() {
2348        let mut config = default_config();
2349        config.buffer_layout.length = usize::from(u16::MAX) + 2;
2350        config.buffer_layout.min_tx_head = 0;
2351        let (pool, _descriptors, _vmo) = Pool::new_test_pool(config);
2352        assert_matches!(pool.alloc_tx_buffer(1).now_or_never(), Some(Err(Error::TxLength)));
2353    }
2354
2355    #[test]
2356    fn vmo_indices_tracking() {
2357        let mut config = default_config();
2358        config.tx_vmos = vec![
2359            TxVmoConfig { vmo_id: 0, num_buffers: 2 },
2360            TxVmoConfig { vmo_id: 1, num_buffers: 4 },
2361        ];
2362
2363        let (pool, _descriptors, _vmos) = Pool::new_test_pool(config);
2364
2365        // Check initial state:
2366        // - first VMO index with free buffers should be 0
2367        {
2368            let state = pool.tx_alloc_state_lock();
2369            assert_eq!(state.first_available_index, 0);
2370        }
2371
2372        // Allocate 1 buffer (takes from VMO 0)
2373        let alloc1 = pool.alloc_tx_now_or_never(1).expect("alloc 1");
2374        {
2375            let state = pool.tx_alloc_state_lock();
2376            // VMO 0 still has 1 free buffer
2377            assert_eq!(state.first_available_index, 0);
2378        }
2379
2380        // Allocate second buffer from VMO 0
2381        let alloc2 = pool.alloc_tx_now_or_never(1).expect("alloc 2");
2382        {
2383            let state = pool.tx_alloc_state_lock();
2384            // VMO 0 has 0 free, so VMO 1 is the first with free.
2385            assert_eq!(state.first_available_index, 1);
2386        }
2387
2388        // Allocate 1 buffer from VMO 1
2389        let alloc3 = pool.alloc_tx_now_or_never(1).expect("alloc 3");
2390        {
2391            let state = pool.tx_alloc_state_lock();
2392            // VMO 1 still has 3 free buffers.
2393            assert_eq!(state.first_available_index, 1);
2394        }
2395
2396        // Allocate remaining buffers from VMO 1 to allocate all buffers
2397        let _alloc4 = pool.alloc_tx_now_or_never(1).expect("alloc 4");
2398        let _alloc5 = pool.alloc_tx_now_or_never(1).expect("alloc 5");
2399        let _alloc6 = pool.alloc_tx_now_or_never(1).expect("alloc 6");
2400        {
2401            let state = pool.tx_alloc_state_lock();
2402            assert_eq!(state.first_available_index, state.free_lists.len());
2403        }
2404
2405        // Free the first buffer (belongs to VMO 0)
2406        drop(alloc1);
2407        {
2408            let state = pool.tx_alloc_state_lock();
2409            // VMO 0 now has 1 free buffer again
2410            assert_eq!(state.first_available_index, 0);
2411        }
2412
2413        // Free the third buffer (belongs to VMO 1)
2414        drop(alloc3);
2415        {
2416            let state = pool.tx_alloc_state_lock();
2417            // VMO 0 still has 1 free buffer, VMO 1 has 4 free.
2418            assert_eq!(state.first_available_index, 0);
2419        }
2420
2421        // Free the second buffer (belongs to VMO 0)
2422        drop(alloc2);
2423        {
2424            let state = pool.tx_alloc_state_lock();
2425            // VMO 0 still has 2 free.
2426            assert_eq!(state.first_available_index, 0);
2427        }
2428    }
2429
2430    #[test]
2431    fn rx_leases() {
2432        let mut executor = fuchsia_async::TestExecutor::new();
2433        let state = RxLeaseHandlingState::new_with_enabled(true);
2434        let mut watcher = RxLeaseWatcher { state: &state };
2435
2436        {
2437            let mut fut = pin!(watcher.wait_until(0));
2438            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
2439        }
2440        {
2441            state.rx_complete();
2442            let mut fut = pin!(watcher.wait_until(1));
2443            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
2444        }
2445        {
2446            let mut fut = pin!(watcher.wait_until(0));
2447            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
2448        }
2449        {
2450            let mut fut = pin!(watcher.wait_until(3));
2451            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2452            state.rx_complete();
2453            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2454            state.rx_complete();
2455            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
2456        }
2457        // Dropping the wait future without seeing it complete restores the
2458        // value.
2459        let counter_before = state.rx_frame_counter.load(atomic::Ordering::SeqCst);
2460        {
2461            let mut fut = pin!(watcher.wait_until(10000));
2462            assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2463        }
2464        let counter_after = state.rx_frame_counter.load(atomic::Ordering::SeqCst);
2465        assert_eq!(counter_before, counter_after);
2466    }
2467
2468    #[test]
2469    #[should_panic(expected = "slice end")]
2470    fn get_slice_out_of_bounds_panic() {
2471        let mut config = default_config();
2472        config.buffer_layout.length = 64;
2473        config.buffer_stride = NonZeroU64::new(64).unwrap();
2474        config.tx_vmos = vec![TxVmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: 1 }];
2475        config.num_rx_buffers = NonZeroU16::new(1).unwrap();
2476
2477        let (mut pool, _descriptors_vmo, _data_vmos) = Pool::new_test_pool(config);
2478        Arc::get_mut(&mut pool)
2479            .expect("there are multiple owners of the underlying VMO")
2480            .fill_sentinel_bytes();
2481
2482        let mut buffer = pool.alloc_tx_buffer_now_or_never(10).expect("failed to alloc buffer");
2483        {
2484            let mut desc = buffer.alloc.descriptor_mut();
2485            desc.set_data_length(4093);
2486        }
2487        let _slice = buffer.as_slice_mut();
2488    }
2489}