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