1use 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
33pub(in crate::session) struct Pool {
35 base: NonNull<u8>,
38 descriptors: Descriptors,
40 pub(in crate::session) tx_alloc_state: Mutex<TxAllocState>,
42 pub(in crate::session) rx_pending: Mutex<Pending<Rx>>,
44 buffer_layout: BufferLayout,
46 rx_leases: RxLeaseHandlingState,
48 vmo_offsets: Vec<usize>,
52 pub(in crate::session) decommittable_tx_vmo_ids: Vec<netdev::VmoId>,
56 decommittable_tx_vmar: Option<zx::Vmar>,
59}
60
61unsafe impl Send for Pool {}
66unsafe impl Sync for Pool {}
67
68pub(in crate::session) struct TxAllocState {
70 requests: VecDeque<TxAllocReq>,
72 free_lists: Vec<TxFreeList>,
73 first_available_index: usize,
77 total_in_use: u16,
79 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
114struct TxFreeList {
122 head: Option<DescId<Tx>>,
125 free: u16,
127 max_free: u16,
129}
130
131pub(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 pub(in crate::session) fn new(config: Config) -> Result<CreatedPool> {
152 let create_and_name_vmo = |size: u64, name: &zx::Name| -> Result<zx::Vmo> {
153 let vmo = zx::Vmo::create(size).map_err(|status| Error::Vmo("create", status))?;
154 vmo.set_name(&name).map_err(|status| Error::Vmo("set_name", status))?;
155 Ok(vmo)
156 };
157
158 let descriptor_count = config
159 .num_rx_buffers
160 .get()
161 .checked_add(config.num_tx_buffers().get())
162 .ok_or(Error::Config("too many descriptors".to_string()))?;
163 let descriptor_vmo_size =
164 u64::try_from(super::NETWORK_DEVICE_DESCRIPTOR_LENGTH * usize::from(descriptor_count))
165 .expect("vmo_size overflows u64");
166 const DESCRIPTORS_VMO_NAME: zx::Name =
167 const_unwrap::const_unwrap_result(zx::Name::new("netdevice:descriptors"));
168 let descriptors_vmo = create_and_name_vmo(descriptor_vmo_size, &DESCRIPTORS_VMO_NAME)?;
169
170 let Config {
171 buffer_stride,
172 num_rx_buffers,
173 tx_vmos,
174 options,
175 buffer_layout,
176 buffer_usage_sample_interval: _,
177 } = config;
178 let num_tx_buffers = {
179 let sum: u16 = tx_vmos.iter().map(|v| v.num_buffers).sum();
180 NonZeroU16::new(sum).expect("num_tx_buffers is zero")
181 };
182 let num_buffers = num_rx_buffers.get() + num_tx_buffers.get();
183 let single_data_vmo = tx_vmos.len() == 1 && tx_vmos[0].vmo_id == DEFAULT_VMO_ID;
184 let decommittable_tx_vmo_ids = if single_data_vmo {
185 vec![]
186 } else {
187 tx_vmos.iter().map(|v| v.vmo_id).collect::<Vec<_>>()
188 };
189
190 let page_size = u64::from(zx::system_get_page_size());
191 let data_vmos = if single_data_vmo {
192 const VMO_NAME: zx::Name =
193 const_unwrap::const_unwrap_result(zx::Name::new("netdevice:data"));
194 let size = (buffer_stride.get() * u64::from(num_buffers)).next_multiple_of(page_size);
195 let data_vmo = create_and_name_vmo(size, &VMO_NAME)?;
196 vec![data_vmo]
197 } else {
198 const RX_VMO_NAME: zx::Name =
199 const_unwrap::const_unwrap_result(zx::Name::new("netdevice:rx_data"));
200 const TX_VMO_NAME: zx::Name =
201 const_unwrap::const_unwrap_result(zx::Name::new("netdevice:tx_data"));
202
203 let rx_size =
204 (buffer_stride.get() * u64::from(num_rx_buffers.get())).next_multiple_of(page_size);
205 let rx_vmo = create_and_name_vmo(rx_size, &RX_VMO_NAME)?;
206
207 std::iter::once(Ok(rx_vmo))
208 .chain(tx_vmos.iter().map(|vmo_config| {
209 let size = (buffer_stride.get() * u64::from(vmo_config.num_buffers))
210 .next_multiple_of(page_size);
211 create_and_name_vmo(size, &TX_VMO_NAME)
212 }))
213 .collect::<Result<Vec<_>>>()?
214 };
215
216 let (descriptors, mut tx_free, mut rx_free) =
217 Descriptors::new(&tx_vmos, num_rx_buffers, buffer_stride, &descriptors_vmo)?;
218
219 for rx_desc in rx_free.iter_mut() {
220 descriptors.borrow_mut(rx_desc).initialize(
221 ChainLength::ZERO,
222 0,
223 buffer_layout.length.try_into().unwrap(),
224 0,
225 );
226 }
227
228 let mut total_len = 0;
229 let mut vmo_offsets = vec![0];
230
231 for vmo in &data_vmos {
232 total_len +=
233 usize::try_from(vmo.get_size().map_err(|status| Error::VmoSize("data", status))?)
234 .expect("usize must be able to hold u64");
235 vmo_offsets.push(total_len);
236 }
237
238 let (total_len, vmo_offsets) = (total_len, vmo_offsets);
240
241 let map_data_vmo = |vmar: &zx::Vmar,
242 data_vmo: usize,
243 vmar_start_offset: usize|
244 -> Result<()> {
245 let offset = vmo_offsets[data_vmo] - vmar_start_offset;
246 let len = vmo_offsets[data_vmo + 1] - vmo_offsets[data_vmo];
247 let _addr = vmar
248 .map(
249 offset,
250 &data_vmos[data_vmo],
251 0,
252 len,
253 zx::VmarFlags::SPECIFIC | zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE,
254 )
255 .map_err(|status| Error::Map("map data vmo", status))?;
256 Ok(())
257 };
258
259 let (vmar, vmar_start) = vmar_root_self()
260 .allocate(
261 0,
262 total_len,
263 zx::VmarFlags::CAN_MAP_READ
264 | zx::VmarFlags::CAN_MAP_WRITE
265 | zx::VmarFlags::CAN_MAP_SPECIFIC,
266 )
267 .map_err(|status| Error::Map("allocate vmar", status))?;
268 let base = NonNull::new(vmar_start as *mut u8).expect("must not be null");
269
270 map_data_vmo(&vmar, 0, 0)?;
271
272 let decommittable_tx_vmar = (!single_data_vmo)
273 .then(|| {
274 const NUM_RX_VMO: usize = 1;
277 let rx_size = vmo_offsets[NUM_RX_VMO];
278 let tx_vmar_len = total_len - rx_size;
279 let (tx_vmar, _tx_vmar_base) = vmar
280 .allocate(
281 rx_size,
282 tx_vmar_len,
283 zx::VmarFlags::SPECIFIC
284 | zx::VmarFlags::CAN_MAP_READ
285 | zx::VmarFlags::CAN_MAP_WRITE
286 | zx::VmarFlags::CAN_MAP_SPECIFIC,
287 )
288 .map_err(|status| Error::Map("allocate tx-vmar", status))?;
289 for i in NUM_RX_VMO..data_vmos.len() {
290 map_data_vmo(&tx_vmar, i, rx_size)?;
291 }
292 Ok::<_, Error>(tx_vmar)
293 })
294 .transpose()?;
295
296 let mut free_lists = Vec::new();
297 for vmo_config in &tx_vmos {
298 let head = tx_free.drain(..usize::from(vmo_config.num_buffers)).rev().fold(
299 None,
300 |head, mut curr| {
301 descriptors.borrow_mut(&mut curr).set_nxt(head);
302 assert_eq!(descriptors.borrow(&curr).vmo_id(), vmo_config.vmo_id);
303 Some(curr)
304 },
305 );
306 free_lists.push(TxFreeList {
307 head,
308 free: vmo_config.num_buffers,
309 max_free: vmo_config.num_buffers,
310 });
311 }
312
313 let tx_alloc_state = Mutex::new(TxAllocState {
314 free_lists,
315 requests: VecDeque::new(),
316 first_available_index: 0,
317 total_in_use: 0,
318 peak_in_use: 0,
319 });
320
321 let pool = Arc::new(Pool {
322 base,
323 descriptors,
324 tx_alloc_state,
325 rx_pending: Mutex::new(Pending::new(rx_free)),
326 buffer_layout,
327 rx_leases: RxLeaseHandlingState::new_with_flags(options),
328 vmo_offsets,
329 decommittable_tx_vmo_ids,
330 decommittable_tx_vmar,
331 });
332
333 Ok(CreatedPool { pool, descriptors_vmo, data_vmos })
334 }
335
336 pub(in crate::session) async fn alloc_tx(
343 self: &Arc<Self>,
344 num_parts: ChainLength,
345 ) -> AllocGuard<Tx> {
346 let receiver = {
347 let mut state = self.tx_alloc_state.lock();
348 match state.try_alloc(num_parts, &self.descriptors) {
349 Some(allocated) => {
350 return AllocGuard::new(allocated, self.clone());
351 }
352 None => {
353 let (request, receiver) = TxAllocReq::new(num_parts);
354 state.requests.push_back(request);
355 receiver
356 }
357 }
358 };
359 receiver.await.unwrap()
361 }
362
363 pub(in crate::session) fn try_alloc_single_part_tx_buffer(
368 self: &Arc<Self>,
369 num_bytes: usize,
370 ) -> Result<Option<SinglePartTxBuffer>> {
371 let BufferLayout { min_tx_data: _, min_tx_head, min_tx_tail, length: buffer_length } =
372 self.buffer_layout;
373 if num_bytes > buffer_length - usize::from(min_tx_head) - usize::from(min_tx_tail) {
374 return Err(Error::TxLength);
375 }
376 self.tx_alloc_state
377 .lock()
378 .try_alloc(ChainLength::try_from(1u8).unwrap(), &self.descriptors)
379 .map(|allocated| -> Result<SinglePartTxBuffer> {
380 let mut alloc = AllocGuard::new(allocated, self.clone());
381 alloc.init(num_bytes)?;
382 let buffer = Buffer::from(alloc);
383 Ok(SinglePartTxBuffer::new(buffer, num_bytes).expect("must be single part"))
384 })
385 .transpose()
386 }
387
388 pub(in crate::session) async fn alloc_tx_buffer(
395 self: &Arc<Self>,
396 num_bytes: usize,
397 ) -> Result<Buffer<Tx>> {
398 self.alloc_tx_buffers(num_bytes).await?.next().unwrap()
399 }
400
401 pub(in crate::session) async fn alloc_tx_buffers<'a>(
414 self: &'a Arc<Self>,
415 num_bytes: usize,
416 ) -> Result<impl Iterator<Item = Result<Buffer<Tx>>> + 'a> {
417 let BufferLayout { min_tx_data, min_tx_head, min_tx_tail, length: buffer_length } =
418 self.buffer_layout;
419 let tx_head = usize::from(min_tx_head);
420 let tx_tail = usize::from(min_tx_tail);
421 let total_bytes = num_bytes.max(min_tx_data) + tx_head + tx_tail;
422 let num_parts = (total_bytes + buffer_length - 1) / buffer_length;
423 let chain_length = ChainLength::try_from(num_parts)?;
424 let first = self.alloc_tx(chain_length).await;
425 let iter = std::iter::once(first)
426 .chain(std::iter::from_fn(move || {
427 let mut state = self.tx_alloc_state.lock();
428 state
429 .try_alloc(chain_length, &self.descriptors)
430 .map(|allocated| AllocGuard::new(allocated, self.clone()))
431 }))
432 .fuse()
435 .map(move |mut alloc| {
436 alloc.init(num_bytes)?;
437 Ok(alloc.into())
438 });
439 Ok(iter)
440 }
441
442 pub(in crate::session) fn free_rx(&self, descs: impl IntoIterator<Item = DescId<Rx>>) {
444 self.rx_pending.lock().extend(descs.into_iter().map(|mut desc| {
445 self.descriptors.borrow_mut(&mut desc).initialize(
446 ChainLength::ZERO,
447 0,
448 self.buffer_layout.length.try_into().unwrap(),
449 0,
450 );
451 desc
452 }));
453 }
454
455 fn free_tx(self: &Arc<Self>, chain: Chained<DescId<Tx>>) {
461 let mut to_fulfill = ArrayVec::<
465 (TxAllocReq, AllocGuard<Tx>),
466 { netdev::MAX_DESCRIPTOR_CHAIN as usize },
467 >::new();
468
469 let mut state = self.tx_alloc_state.lock();
470 state.total_in_use -= u16::from(chain.len.get());
471 {
472 let vmo_id =
473 self.descriptors.borrow(chain.first().expect("chain is not empty")).vmo_id();
474 let idx = self.free_list_index(vmo_id);
475 if idx < state.first_available_index {
476 state.first_available_index = idx;
477 }
478
479 let mut descs = chain.into_iter();
480 state.free_lists[idx].free += u16::try_from(descs.len()).unwrap();
481 let head = descs.next();
482 let old_head = std::mem::replace(&mut state.free_lists[idx].head, head);
483 let mut tail = descs.last();
484 let mut tail_ref = self.descriptors.borrow_mut(
485 tail.as_mut().unwrap_or_else(|| state.free_lists[idx].head.as_mut().unwrap()),
486 );
487 tail_ref.set_nxt(old_head);
488 }
489
490 while let Some(req) = state.requests.front() {
493 if req.sender.is_canceled() {
498 let _cancelled: Option<TxAllocReq> = state.requests.pop_front();
499 continue;
500 }
501 let size = req.size;
502 match state.try_alloc(size, &self.descriptors) {
503 Some(descs) => {
504 let req = state.requests.pop_front().unwrap();
506 to_fulfill.push((req, AllocGuard::new(descs, self.clone())));
507
508 if to_fulfill.is_full() {
512 drop(state);
513 for (req, alloc) in to_fulfill.drain(..) {
514 req.fulfill(alloc)
515 }
516 state = self.tx_alloc_state.lock();
517 }
518 }
519 None => break,
520 }
521 }
522
523 drop(state);
525 for (req, alloc) in to_fulfill {
527 req.fulfill(alloc)
528 }
529 }
530
531 pub(in crate::session) fn tx_completed(self: &Arc<Self>, head: DescId<Tx>) -> Result<()> {
535 let chain = self.descriptors.chain(head).collect::<Result<Chained<_>>>()?;
536 Ok(self.free_tx(chain))
537 }
538
539 pub(in crate::session) fn rx_completed(
545 self: &Arc<Self>,
546 head: DescId<Rx>,
547 ) -> Result<Buffer<Rx>> {
548 let descs = self.descriptors.chain(head).collect::<Result<Chained<_>>>()?;
549 let alloc = AllocGuard::new(descs, self.clone());
550 Ok(alloc.into())
551 }
552
553 fn get_slice_layout<K: AllocKind>(&self, desc: &super::Descriptor<K>) -> (usize, usize) {
554 let vmo_id = usize::from(desc.vmo_id());
555 if vmo_id >= self.vmo_offsets.len() - 1 {
556 panic!("invalid vmo_id {} for vmo_offsets of len {}", vmo_id, self.vmo_offsets.len());
557 }
558 let vmo_offset = self.vmo_offsets[vmo_id];
559 let next_vmo_offset = self.vmo_offsets[vmo_id + 1];
560
561 let desc_offset = desc.offset();
562 let head_len = u64::from(desc.head_length());
563 let data_len = u64::from(desc.data_length());
564
565 let total_offset = desc_offset
566 .checked_add(head_len)
567 .and_then(|o| usize::try_from(o).ok())
568 .and_then(|o| o.checked_add(vmo_offset))
569 .unwrap_or_else(|| panic!("offset calculation overflowed"));
570
571 let len =
572 usize::try_from(data_len).unwrap_or_else(|_| panic!("data_length overflowed usize"));
573
574 let end = total_offset
575 .checked_add(len)
576 .unwrap_or_else(|| panic!("end offset calculation overflowed"));
577
578 if end > next_vmo_offset {
579 panic!("slice end {} out of VMO bounds {}", end, next_vmo_offset);
580 }
581
582 (total_offset, len)
583 }
584
585 fn get_slice<'a, K: AllocKind>(&self, desc: &'a DescId<K>) -> &'a [u8] {
586 let desc = self.descriptors.borrow(desc);
587 let (offset, len) = self.get_slice_layout(&desc);
588 unsafe {
593 let ptr = self.base.as_ptr().add(offset);
594 std::slice::from_raw_parts(ptr, len)
595 }
596 }
597
598 fn get_slice_mut<'a, K: AllocKind>(&self, desc: &'a mut DescId<K>) -> &'a mut [u8] {
599 let desc = self.descriptors.borrow_mut(desc);
600 let (offset, len) = self.get_slice_layout(&*desc);
601 unsafe {
606 let ptr = self.base.as_ptr().add(offset);
607 std::slice::from_raw_parts_mut(ptr, len)
608 }
609 }
610
611 pub(in crate::session) fn decommit_tx_vmo(&self, tx_vmo_idx: TxVmoIndex) -> Result<()> {
612 let tx_vmar = self
613 .decommittable_tx_vmar
614 .as_ref()
615 .ok_or(Error::Vmo("decommit", zx::Status::NOT_SUPPORTED))?;
616 let vmo_idx = tx_vmo_idx + usize::from(self.decommittable_tx_vmo_ids[0]);
617 let start_offset = self.vmo_offsets[vmo_idx];
618 let end_offset = self.vmo_offsets[vmo_idx + 1];
619 let len = end_offset - start_offset;
620 let addr = self.base.addr().get() + start_offset;
621 tx_vmar
622 .op_range(zx::VmarOp::DECOMMIT, addr, len)
623 .map_err(|status| Error::Vmo("decommit", status))
624 }
625
626 pub(in crate::session) fn has_decommittable_tx_vmo(&self) -> bool {
627 self.decommittable_tx_vmar.is_some()
628 }
629
630 fn free_list_index(&self, vmo_id: u8) -> usize {
631 if self.decommittable_tx_vmo_ids.is_empty() {
632 0
634 } else {
635 usize::from(vmo_id - self.decommittable_tx_vmo_ids[0])
641 }
642 }
643}
644
645impl Drop for Pool {
646 fn drop(&mut self) {
647 let bytes = *self.vmo_offsets.last().unwrap();
648 unsafe {
649 vmar_root_self()
650 .unmap(self.base.as_ptr() as usize, bytes)
651 .expect("failed to unmap VMO for Pool")
652 }
653 }
654}
655
656impl TxFreeList {
657 fn try_alloc(
661 &mut self,
662 num_parts: ChainLength,
663 descriptors: &Descriptors,
664 ) -> Option<Chained<DescId<Tx>>> {
665 if u16::from(num_parts.get()) > self.free {
666 return None;
667 }
668
669 let free_list = std::iter::from_fn(|| -> Option<DescId<Tx>> {
670 let new_head = self.head.as_ref().and_then(|head| {
671 let nxt = descriptors.borrow(head).nxt();
672 nxt.map(|id| unsafe {
673 DescId::from_raw(id)
676 })
677 });
678 std::mem::replace(&mut self.head, new_head)
679 });
680 let allocated = free_list.take(num_parts.get().into()).collect::<Chained<_>>();
681 assert_eq!(allocated.len(), num_parts.into());
682 self.free -= u16::from(num_parts.get());
683 Some(allocated)
684 }
685}
686
687pub struct Buffer<K: AllocKind> {
689 alloc: AllocGuard<K>,
691}
692
693impl<K: AllocKind> Buffer<K> {
694 pub(in crate::session) fn vmo_id(&self) -> u8 {
695 let desc_id = unsafe { self.alloc.descs.storage[0].assume_init_ref() };
697 self.alloc.pool.descriptors.borrow(desc_id).vmo_id()
698 }
699
700 pub fn len(&self) -> usize {
702 self.parts().map(|s| s.len()).sum()
703 }
704
705 fn parts(&self) -> impl Iterator<Item = &[u8]> + '_ {
707 self.alloc.descs.iter().map(|desc| self.alloc.pool.get_slice(desc))
708 }
709
710 fn parts_mut(&mut self) -> impl Iterator<Item = &mut [u8]> + '_ {
712 self.alloc.descs.iter_mut().map(|desc| self.alloc.pool.get_slice_mut(desc))
713 }
714
715 pub(in crate::session) fn leak(mut self) -> DescId<K> {
717 let descs = std::mem::replace(&mut self.alloc.descs, Chained::empty());
718 descs.into_iter().next().unwrap()
719 }
720
721 pub fn as_slice(&self) -> Option<&[u8]> {
723 if self.alloc.len() != 1 {
724 return None;
725 }
726 self.parts().next()
727 }
728
729 pub fn as_slice_mut(&mut self) -> Option<&mut [u8]> {
731 if self.alloc.len() != 1 {
732 return None;
733 }
734 self.parts_mut().next()
735 }
736
737 pub fn io(&self) -> BufferIORef<'_, K> {
739 let mut len = 0;
740 let parts: Chained<&[u8]> = self.parts().inspect(|s| len += s.len()).collect();
741 BufferIO { parts, pos: 0, len, _marker: std::marker::PhantomData }
742 }
743
744 pub fn io_mut(&mut self) -> BufferIOMut<'_, K> {
746 let mut len = 0;
747 let parts: Chained<&mut [u8]> = self.parts_mut().inspect(|s| len += s.len()).collect();
748 BufferIO { parts, pos: 0, len, _marker: std::marker::PhantomData }
749 }
750}
751
752pub struct TxMetadataMut<'a> {
758 desc: DescRefMut<'a, Tx>,
759}
760
761impl<'a> TxMetadataMut<'a> {
762 pub fn set_port(&mut self, port: Port) {
764 self.desc.set_port(port);
765 }
766
767 pub fn set_frame_type(&mut self, frame_type: netdev::FrameType) {
769 self.desc.set_frame_type(frame_type);
770 }
771
772 pub fn set_tx_flags(&mut self, flags: netdev::TxFlags) {
774 self.desc.set_tx_flags(flags);
775 }
776
777 pub fn set_generic_csum_offload(&mut self, start: u16, offset: u16) {
779 self.desc.set_generic_csum_offload(start, offset);
780 }
781}
782
783impl Buffer<Tx> {
784 pub fn meta_mut(&mut self) -> TxMetadataMut<'_> {
786 TxMetadataMut { desc: self.alloc.descriptor_mut() }
787 }
788
789 pub fn shrink_to(&mut self, mut new_len: usize) -> Result<()> {
797 let current_len = self.len();
798
799 if new_len > current_len {
800 return Err(Error::TxLength);
801 }
802
803 let min_tx_data = usize::from(self.alloc.pool.buffer_layout.min_tx_data);
804 new_len = new_len.max(min_tx_data);
805
806 let layouts = self.alloc.calculate_descriptor_layouts(new_len)?;
807
808 for (desc_id, DescriptorLayout { data_length, tail_length, .. }) in
809 self.alloc.descs.iter_mut().zip(layouts)
810 {
811 let mut descriptor = self.alloc.pool.descriptors.borrow_mut(desc_id);
812 descriptor.set_data_length(data_length);
813 descriptor.set_tail_length(tail_length);
814 }
815 Ok(())
816 }
817}
818
819pub enum ChecksumRxOffloading {
821 Offloaded(NonZeroU16),
823}
824
825pub struct RxMetadata<'a> {
831 desc: DescRef<'a, Rx>,
832}
833
834impl<'a> RxMetadata<'a> {
835 pub fn rx_flags(&self) -> Result<netdev::RxFlags> {
837 self.desc.rx_flags()
838 }
839
840 pub fn rx_checksum_offloading(&self) -> Option<ChecksumRxOffloading> {
842 self.desc.rx_checksum_offloading()
843 }
844
845 pub fn frame_type(&self) -> Result<netdev::FrameType> {
847 self.desc.frame_type()
848 }
849
850 pub fn port(&self) -> Port {
852 self.desc.port()
853 }
854}
855
856impl Buffer<Rx> {
857 pub fn meta(&self) -> RxMetadata<'_> {
859 RxMetadata { desc: self.alloc.descriptor() }
860 }
861}
862
863impl<K: AllocKind> Debug for Buffer<K> {
864 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
865 let Self { alloc } = self;
866 f.debug_struct("Buffer").field("alloc", alloc).finish()
867 }
868}
869
870pub struct SinglePartTxBuffer(Buffer<Tx>);
873
874impl SinglePartTxBuffer {
875 pub fn new(buffer: Buffer<Tx>, len: usize) -> Option<Self> {
878 if buffer.alloc.len() != 1 {
879 None
880 } else {
881 let cap = usize::try_from(buffer.alloc.descriptor().data_length())
882 .expect("u32 must fit in a usize");
883 if cap < len { None } else { Some(Self(buffer)) }
884 }
885 }
886
887 pub fn into_inner(self) -> Buffer<Tx> {
889 let Self(buffer) = self;
890 buffer
891 }
892}
893
894impl AsRef<[u8]> for SinglePartTxBuffer {
895 fn as_ref(&self) -> &[u8] {
896 let desc = unsafe { self.0.alloc.descs.storage[0].assume_init_ref() };
899 self.0.alloc.pool.get_slice(desc)
900 }
901}
902
903impl AsMut<[u8]> for SinglePartTxBuffer {
904 fn as_mut(&mut self) -> &mut [u8] {
905 let desc = unsafe { self.0.alloc.descs.storage[0].assume_init_mut() };
908 self.0.alloc.pool.get_slice_mut(desc)
909 }
910}
911
912impl packet::FragmentedBuffer for SinglePartTxBuffer {
913 fn len(&self) -> usize {
914 let desc = self.0.alloc.descriptor();
915 usize::try_from(desc.data_length()).expect("u32 must fit in a usize")
916 }
917
918 fn with_bytes<'a, R, F>(&'a self, f: F) -> R
919 where
920 F: for<'b> FnOnce(packet::FragmentedBytes<'b, 'a>) -> R,
921 {
922 f(packet::FragmentedBytes::new(&mut [self.as_ref()][..]))
923 }
924}
925
926pub struct BufferIO<T, K: AllocKind> {
931 parts: Chained<T>,
932 pos: usize,
933 len: usize,
934 _marker: std::marker::PhantomData<K>,
935}
936
937pub type BufferIORef<'a, K> = BufferIO<&'a [u8], K>;
938pub type BufferIOMut<'a, K> = BufferIO<&'a mut [u8], K>;
939
940impl<T> BufferIO<T, Tx>
941where
942 T: AsMut<[u8]>,
943{
944 pub fn write_at(&mut self, mut offset: usize, src: &[u8]) -> usize {
956 let mut total = 0;
957
958 for slice in self.parts.iter_mut() {
959 let slice = slice.as_mut();
960 if offset < slice.len() {
961 let available = slice.len() - offset;
962 let to_copy = std::cmp::min(src.len() - total, available);
963 slice[offset..offset + to_copy].copy_from_slice(&src[total..total + to_copy]);
964 total += to_copy;
965 offset = 0;
966 if total == src.len() {
967 break;
968 }
969 } else {
970 offset -= slice.len();
971 }
972 }
973 total
974 }
975}
976
977impl<T, K: AllocKind> BufferIO<T, K>
978where
979 T: AsRef<[u8]>,
980{
981 pub fn read_at(&self, mut offset: usize, dst: &mut [u8]) -> usize {
992 let mut total = 0;
993
994 for slice in self.parts.iter() {
995 let slice = slice.as_ref();
996 if offset < slice.len() {
997 let available = slice.len() - offset;
998 let to_copy = std::cmp::min(dst.len() - total, available);
999 dst[total..total + to_copy].copy_from_slice(&slice[offset..offset + to_copy]);
1000 total += to_copy;
1001 offset = 0;
1002 if total == dst.len() {
1003 break;
1004 }
1005 } else {
1006 offset -= slice.len();
1007 }
1008 }
1009 total
1010 }
1011}
1012
1013struct Chained<T> {
1015 storage: [MaybeUninit<T>; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1016 len: ChainLength,
1017}
1018
1019impl<T> Deref for Chained<T> {
1020 type Target = [T];
1021
1022 fn deref(&self) -> &Self::Target {
1023 unsafe { std::mem::transmute(&self.storage[..self.len.into()]) }
1025 }
1026}
1027
1028impl<T> DerefMut for Chained<T> {
1029 fn deref_mut(&mut self) -> &mut Self::Target {
1030 unsafe { std::mem::transmute(&mut self.storage[..self.len.into()]) }
1032 }
1033}
1034
1035impl<T> Drop for Chained<T> {
1036 fn drop(&mut self) {
1037 unsafe {
1039 std::ptr::drop_in_place(self.deref_mut());
1040 }
1041 }
1042}
1043
1044impl<T: Debug> Debug for Chained<T> {
1045 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1046 f.debug_list().entries(self.iter()).finish()
1047 }
1048}
1049
1050impl<T> Chained<T> {
1051 #[allow(clippy::uninit_assumed_init)]
1052 fn empty() -> Self {
1053 Self { storage: unsafe { MaybeUninit::uninit().assume_init() }, len: ChainLength::ZERO }
1060 }
1061}
1062
1063impl<T> FromIterator<T> for Chained<T> {
1064 fn from_iter<I: IntoIterator<Item = T>>(elements: I) -> Self {
1068 let mut result = Self::empty();
1069 let mut len = 0u8;
1070 for (idx, e) in elements.into_iter().enumerate() {
1071 result.storage[idx] = MaybeUninit::new(e);
1072 len += 1;
1073 }
1074 result.len = ChainLength::try_from(len).unwrap();
1077 result
1078 }
1079}
1080
1081impl<T> IntoIterator for Chained<T> {
1082 type Item = T;
1083 type IntoIter = ChainedIter<T>;
1084
1085 fn into_iter(mut self) -> Self::IntoIter {
1086 let len = self.len;
1087 self.len = ChainLength::ZERO;
1088 #[allow(clippy::uninit_assumed_init)]
1095 let storage =
1096 std::mem::replace(&mut self.storage, unsafe { MaybeUninit::uninit().assume_init() });
1097 ChainedIter { storage, len, consumed: 0 }
1098 }
1099}
1100
1101struct ChainedIter<T> {
1102 storage: [MaybeUninit<T>; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1103 len: ChainLength,
1104 consumed: u8,
1105}
1106
1107impl<T> Iterator for ChainedIter<T> {
1108 type Item = T;
1109
1110 fn next(&mut self) -> Option<Self::Item> {
1111 if self.consumed < self.len.get() {
1112 let value = unsafe {
1115 std::mem::replace(
1116 &mut self.storage[usize::from(self.consumed)],
1117 MaybeUninit::uninit(),
1118 )
1119 .assume_init()
1120 };
1121 self.consumed += 1;
1122 Some(value)
1123 } else {
1124 None
1125 }
1126 }
1127
1128 fn size_hint(&self) -> (usize, Option<usize>) {
1129 let len = usize::from(self.len.get() - self.consumed);
1130 (len, Some(len))
1131 }
1132}
1133
1134impl<T> ExactSizeIterator for ChainedIter<T> {}
1135
1136impl<T> Drop for ChainedIter<T> {
1137 fn drop(&mut self) {
1138 unsafe {
1140 std::ptr::drop_in_place(std::mem::transmute::<_, &mut [T]>(
1141 &mut self.storage[self.consumed.into()..self.len.into()],
1142 ));
1143 }
1144 }
1145}
1146
1147pub(in crate::session) struct AllocGuard<K: AllocKind> {
1149 descs: Chained<DescId<K>>,
1150 pool: Arc<Pool>,
1151}
1152
1153impl<K: AllocKind> Debug for AllocGuard<K> {
1154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1155 let Self { descs, pool: _ } = self;
1156 f.debug_struct("AllocGuard").field("descs", descs).finish()
1157 }
1158}
1159
1160impl<K: AllocKind> AllocGuard<K> {
1161 fn new(descs: Chained<DescId<K>>, pool: Arc<Pool>) -> Self {
1162 Self { descs, pool }
1163 }
1164
1165 fn descriptors(&self) -> impl Iterator<Item = DescRef<'_, K>> + '_ {
1167 self.descs.iter().map(move |desc| self.pool.descriptors.borrow(desc))
1168 }
1169
1170 fn descriptors_mut(&mut self) -> impl Iterator<Item = DescRefMut<'_, K>> + '_ {
1172 let descriptors = &self.pool.descriptors;
1173 self.descs.iter_mut().map(move |desc| descriptors.borrow_mut(desc))
1174 }
1175
1176 fn descriptor(&self) -> DescRef<'_, K> {
1178 self.descriptors().next().expect("descriptors must not be empty")
1179 }
1180
1181 fn descriptor_mut(&mut self) -> DescRefMut<'_, K> {
1183 self.descriptors_mut().next().expect("descriptors must not be empty")
1184 }
1185}
1186
1187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1188struct DescriptorLayout {
1189 chain_length: ChainLength,
1190 head_length: u16,
1191 data_length: u32,
1192 tail_length: u16,
1193}
1194
1195impl AllocGuard<Tx> {
1196 fn calculate_descriptor_layouts(&self, target_len: usize) -> Result<Chained<DescriptorLayout>> {
1205 let len = self.len();
1206 let BufferLayout { min_tx_head, min_tx_tail, length: buffer_length, .. } =
1207 self.pool.buffer_layout;
1208
1209 let mut remaining_target = target_len;
1210 (0..len)
1211 .rev()
1212 .map(|clen| {
1213 let chain_length = ChainLength::try_from(clen).unwrap();
1214 let head_length = if clen + 1 == len { min_tx_head } else { 0 };
1215 let mut tail_length = if clen == 0 { min_tx_tail } else { 0 };
1216
1217 let available_bytes = u32::try_from(
1220 buffer_length - usize::from(head_length) - usize::from(tail_length),
1221 )
1222 .unwrap();
1223
1224 let data_length = match u32::try_from(remaining_target) {
1225 Ok(target) => {
1226 if target < available_bytes {
1227 let excess = available_bytes - target;
1231 tail_length = u16::try_from(excess)
1232 .ok_checked::<TryFromIntError>()
1233 .and_then(|tail_adjustment| {
1234 tail_length.checked_add(tail_adjustment)
1235 })
1236 .ok_or(Error::TxLength)?;
1237 }
1238 target.min(available_bytes)
1239 }
1240 Err(TryFromIntError { .. }) => available_bytes,
1241 };
1242
1243 let data_length_usize =
1244 usize::try_from(data_length).expect("u32 must fit in a usize");
1245 remaining_target = remaining_target.saturating_sub(data_length_usize);
1246
1247 Ok::<_, Error>(DescriptorLayout {
1248 chain_length,
1249 head_length,
1250 data_length,
1251 tail_length,
1252 })
1253 })
1254 .collect()
1255 }
1256
1257 fn init(&mut self, requested_bytes: usize) -> Result<()> {
1272 let min_tx_data = self.pool.buffer_layout.min_tx_data;
1273 let target_len = requested_bytes.max(usize::from(min_tx_data));
1274 let layouts = self.calculate_descriptor_layouts(target_len)?;
1275
1276 let mut remaining_requested = requested_bytes;
1277
1278 for (desc_id, DescriptorLayout { chain_length, head_length, data_length, tail_length }) in
1279 self.descs.iter_mut().zip(layouts)
1280 {
1281 {
1283 let mut descriptor = self.pool.descriptors.borrow_mut(desc_id);
1284 descriptor.initialize(chain_length, head_length, data_length, tail_length);
1285 }
1286
1287 let data_length_usize = usize::try_from(data_length).expect("u32 must fit in a usize");
1288 let requested_in_part = std::cmp::min(remaining_requested, data_length_usize);
1289 let pad_in_part = data_length_usize - requested_in_part;
1290
1291 if pad_in_part > 0 {
1303 let slice = self.pool.get_slice_mut(desc_id);
1304 slice[requested_in_part..requested_in_part + pad_in_part].fill(0);
1305 }
1306
1307 remaining_requested -= requested_in_part;
1308 }
1309 Ok(())
1310 }
1311}
1312
1313impl<K: AllocKind> Drop for AllocGuard<K> {
1314 fn drop(&mut self) {
1315 if self.is_empty() {
1316 return;
1317 }
1318 K::free(private::Allocation(self));
1319 }
1320}
1321
1322impl<K: AllocKind> Deref for AllocGuard<K> {
1323 type Target = [DescId<K>];
1324
1325 fn deref(&self) -> &Self::Target {
1326 self.descs.deref()
1327 }
1328}
1329
1330impl<K: AllocKind> From<AllocGuard<K>> for Buffer<K> {
1331 fn from(alloc: AllocGuard<K>) -> Self {
1332 Self { alloc }
1333 }
1334}
1335
1336impl<T, K: AllocKind> Read for BufferIO<T, K>
1337where
1338 T: AsRef<[u8]>,
1339{
1340 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1341 let read_len = self.read_at(self.pos, buf);
1342 self.pos += read_len;
1343 Ok(read_len)
1344 }
1345}
1346
1347impl<T> Write for BufferIO<T, Tx>
1348where
1349 T: AsMut<[u8]>,
1350{
1351 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1352 let write_len = self.write_at(self.pos, buf);
1353 self.pos += write_len;
1354 Ok(write_len)
1355 }
1356
1357 fn flush(&mut self) -> std::io::Result<()> {
1358 Ok(())
1359 }
1360}
1361
1362impl<T, K: AllocKind> Seek for BufferIO<T, K> {
1363 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
1364 let pos = match pos {
1365 SeekFrom::Start(offset) => offset,
1366 SeekFrom::End(offset) => {
1367 let end = i64::try_from(self.len).unwrap();
1368 u64::try_from(end.wrapping_add(offset)).unwrap()
1369 }
1370 SeekFrom::Current(offset) => {
1371 let current = i64::try_from(self.pos).map_err(|TryFromIntError { .. }| {
1372 std::io::Error::from(std::io::ErrorKind::InvalidInput)
1373 })?;
1374 u64::try_from(current.wrapping_add(offset)).unwrap()
1375 }
1376 };
1377 self.pos = usize::try_from(pos).map_err(|TryFromIntError { .. }| {
1378 std::io::Error::from(std::io::ErrorKind::InvalidInput)
1379 })?;
1380 Ok(pos)
1381 }
1382}
1383
1384struct TxAllocReq {
1386 sender: Sender<AllocGuard<Tx>>,
1387 size: ChainLength,
1388}
1389
1390impl TxAllocReq {
1391 fn new(size: ChainLength) -> (Self, Receiver<AllocGuard<Tx>>) {
1392 let (sender, receiver) = channel();
1393 (TxAllocReq { sender, size }, receiver)
1394 }
1395
1396 fn fulfill(self, guard: AllocGuard<Tx>) {
1404 let Self { sender, size: _ } = self;
1405 match sender.send(guard) {
1406 Ok(()) => (),
1407 Err(guard) => {
1408 drop(guard);
1411 }
1412 }
1413 }
1414}
1415
1416mod private {
1419 use super::{AllocKind, Rx, Tx};
1420 pub trait Sealed: 'static + Sized {}
1421 impl Sealed for Rx {}
1422 impl Sealed for Tx {}
1423
1424 pub struct Allocation<'a, K: AllocKind>(pub(super) &'a mut super::AllocGuard<K>);
1428}
1429
1430pub trait AllocKind: private::Sealed {
1433 const REFL: AllocKindRefl;
1435
1436 fn free(alloc: private::Allocation<'_, Self>);
1438}
1439
1440pub enum Tx {}
1442pub enum Rx {}
1444
1445pub enum AllocKindRefl {
1447 Tx,
1448 Rx,
1449}
1450
1451impl AllocKindRefl {
1452 pub(in crate::session) fn as_str(&self) -> &'static str {
1453 match self {
1454 AllocKindRefl::Tx => "Tx",
1455 AllocKindRefl::Rx => "Rx",
1456 }
1457 }
1458}
1459
1460impl AllocKind for Tx {
1461 const REFL: AllocKindRefl = AllocKindRefl::Tx;
1462
1463 fn free(alloc: private::Allocation<'_, Self>) {
1464 let private::Allocation(AllocGuard { pool, descs }) = alloc;
1465 pool.free_tx(std::mem::replace(descs, Chained::empty()));
1466 }
1467}
1468
1469impl AllocKind for Rx {
1470 const REFL: AllocKindRefl = AllocKindRefl::Rx;
1471
1472 fn free(alloc: private::Allocation<'_, Self>) {
1473 let private::Allocation(AllocGuard { pool, descs }) = alloc;
1474 pool.free_rx(std::mem::replace(descs, Chained::empty()));
1475 pool.rx_leases.rx_complete();
1476 }
1477}
1478
1479pub(in crate::session) struct RxLeaseHandlingState {
1481 can_watch_rx_leases: AtomicBool,
1482 rx_frame_counter: AtomicU64,
1492 rx_lease_waker: AtomicWaker,
1493}
1494
1495impl RxLeaseHandlingState {
1496 fn new_with_flags(flags: netdev::SessionFlags) -> Self {
1497 Self::new_with_enabled(flags.contains(netdev::SessionFlags::RECEIVE_RX_POWER_LEASES))
1498 }
1499
1500 fn new_with_enabled(enabled: bool) -> Self {
1501 Self {
1502 can_watch_rx_leases: AtomicBool::new(enabled),
1503 rx_frame_counter: AtomicU64::new(0),
1504 rx_lease_waker: AtomicWaker::new(),
1505 }
1506 }
1507
1508 fn rx_complete(&self) {
1511 let Self { can_watch_rx_leases: _, rx_frame_counter, rx_lease_waker } = self;
1512 let prev = rx_frame_counter.fetch_add(1, atomic::Ordering::SeqCst);
1513
1514 if prev == u64::MAX {
1517 rx_lease_waker.wake();
1518 }
1519 }
1520}
1521
1522pub(in crate::session) trait RxLeaseHandlingStateContainer {
1525 fn lease_handling_state(&self) -> &RxLeaseHandlingState;
1526}
1527
1528impl<T: Borrow<RxLeaseHandlingState>> RxLeaseHandlingStateContainer for T {
1529 fn lease_handling_state(&self) -> &RxLeaseHandlingState {
1530 self.borrow()
1531 }
1532}
1533
1534impl RxLeaseHandlingStateContainer for Arc<Pool> {
1535 fn lease_handling_state(&self) -> &RxLeaseHandlingState {
1536 &self.rx_leases
1537 }
1538}
1539
1540pub(in crate::session) struct RxLeaseWatcher<T> {
1542 state: T,
1543}
1544
1545impl<T: RxLeaseHandlingStateContainer> RxLeaseWatcher<T> {
1546 pub(in crate::session) fn new(state: T) -> Self {
1553 assert!(
1554 state.lease_handling_state().can_watch_rx_leases.swap(false, atomic::Ordering::SeqCst),
1555 "can't watch rx leases"
1556 );
1557 Self { state }
1558 }
1559
1560 pub(in crate::session) async fn wait_until(&mut self, hold_until_frame: u64) {
1569 let RxLeaseHandlingState { can_watch_rx_leases: _, rx_frame_counter, rx_lease_waker } =
1578 self.state.lease_handling_state();
1579
1580 let prev = rx_frame_counter.fetch_sub(hold_until_frame, atomic::Ordering::SeqCst);
1581 let _guard = scopeguard::guard((), |()| {
1584 let _: u64 = rx_frame_counter.fetch_add(hold_until_frame, atomic::Ordering::SeqCst);
1585 });
1586
1587 if prev >= hold_until_frame {
1589 return;
1590 }
1591 let threshold = prev.wrapping_sub(hold_until_frame);
1594 futures::future::poll_fn(|cx| {
1595 let v = rx_frame_counter.load(atomic::Ordering::SeqCst);
1596 if v < threshold {
1597 return Poll::Ready(());
1598 }
1599 rx_lease_waker.register(cx.waker());
1600 let v = rx_frame_counter.load(atomic::Ordering::SeqCst);
1601 if v < threshold {
1602 return Poll::Ready(());
1603 }
1604 Poll::Pending
1605 })
1606 .await;
1607 }
1608}
1609
1610#[cfg(test)]
1611mod tests {
1612
1613 use super::*;
1614
1615 use assert_matches::assert_matches;
1616 use fuchsia_async as fasync;
1617 use futures::future::FutureExt;
1618 use test_case::test_case;
1619
1620 use std::collections::HashSet;
1621 use std::num::{NonZeroU16, NonZeroU64, NonZeroUsize};
1622 use std::pin::pin;
1623 use std::task::Poll;
1624
1625 use crate::session::tx::TxVmoConfig;
1626
1627 const DEFAULT_MIN_TX_BUFFER_HEAD: u16 = 4;
1628 const DEFAULT_MIN_TX_BUFFER_TAIL: u16 = 8;
1629 const DEFAULT_BUFFER_LENGTH: NonZeroUsize = NonZeroUsize::new(64).unwrap();
1631 const DEFAULT_TX_BUFFERS: NonZeroU16 = NonZeroU16::new(8).unwrap();
1632 const DEFAULT_RX_BUFFERS: NonZeroU16 = NonZeroU16::new(8).unwrap();
1633 const MAX_BUFFER_BYTES: usize = DEFAULT_BUFFER_LENGTH.get()
1634 * netdev::MAX_DESCRIPTOR_CHAIN as usize
1635 - DEFAULT_MIN_TX_BUFFER_HEAD as usize
1636 - DEFAULT_MIN_TX_BUFFER_TAIL as usize;
1637
1638 const SENTINEL_BYTE: u8 = 0xab;
1639 const WRITE_BYTE: u8 = 1;
1640 const PAD_BYTE: u8 = 0;
1641
1642 fn default_config() -> Config {
1643 Config {
1644 buffer_stride: NonZeroU64::new(DEFAULT_BUFFER_LENGTH.get() as u64).unwrap(),
1645 num_rx_buffers: DEFAULT_RX_BUFFERS,
1646 tx_vmos: vec![TxVmoConfig {
1647 vmo_id: DEFAULT_VMO_ID,
1648 num_buffers: DEFAULT_TX_BUFFERS.get(),
1649 }],
1650 options: netdev::SessionFlags::empty(),
1651 buffer_layout: BufferLayout {
1652 length: DEFAULT_BUFFER_LENGTH.get(),
1653 min_tx_head: DEFAULT_MIN_TX_BUFFER_HEAD,
1654 min_tx_tail: DEFAULT_MIN_TX_BUFFER_TAIL,
1655 min_tx_data: 0,
1656 },
1657 buffer_usage_sample_interval: std::time::Duration::from_secs(1),
1658 }
1659 }
1660
1661 impl Pool {
1662 fn new_test_pool(config: Config) -> (Arc<Self>, zx::Vmo, Vec<zx::Vmo>) {
1663 let CreatedPool { pool, descriptors_vmo, data_vmos } =
1664 Pool::new(config).expect("failed to create pool");
1665 (pool, descriptors_vmo, data_vmos)
1666 }
1667
1668 fn new_test_default() -> Arc<Self> {
1669 let (pool, _descriptors, _data) = Pool::new_test_pool(default_config());
1670 pool
1671 }
1672
1673 fn tx_alloc_state_lock(&self) -> fuchsia_sync::MutexGuard<'_, TxAllocState> {
1674 self.tx_alloc_state.lock()
1675 }
1676
1677 async fn alloc_tx_checked(self: &Arc<Self>, n: u8) -> AllocGuard<Tx> {
1678 self.alloc_tx(ChainLength::try_from(n).expect("failed to convert to chain length"))
1679 .await
1680 }
1681
1682 fn alloc_tx_now_or_never(self: &Arc<Self>, n: u8) -> Option<AllocGuard<Tx>> {
1683 self.alloc_tx_checked(n).now_or_never()
1684 }
1685
1686 fn alloc_tx_all(self: &Arc<Self>, n: u8) -> Vec<AllocGuard<Tx>> {
1687 std::iter::from_fn(|| self.alloc_tx_now_or_never(n)).collect()
1688 }
1689
1690 fn alloc_tx_buffer_now_or_never(self: &Arc<Self>, num_bytes: usize) -> Option<Buffer<Tx>> {
1691 self.alloc_tx_buffer(num_bytes)
1692 .now_or_never()
1693 .transpose()
1694 .expect("invalid arguments for alloc_tx_buffer")
1695 }
1696
1697 fn set_min_tx_buffer_length(self: &mut Arc<Self>, length: usize) {
1698 Arc::get_mut(self).unwrap().buffer_layout.min_tx_data = length;
1699 }
1700
1701 fn fill_sentinel_bytes(&mut self) {
1702 let bytes = *self.vmo_offsets.last().unwrap();
1705 unsafe { std::ptr::write_bytes(self.base.as_ptr(), SENTINEL_BYTE, bytes) };
1706 }
1707 }
1708
1709 impl Buffer<Tx> {
1710 fn check_write_and_pad(&mut self, offset: usize, pad_size: usize) {
1714 {
1715 let mut io = self.io_mut();
1716 assert_eq!(io.write_at(offset, &[WRITE_BYTE][..]), 1);
1717 }
1718 assert_eq!(self.len(), pad_size);
1719 const INIT_BYTE: u8 = 42;
1722 let mut read_buf = vec![INIT_BYTE; pad_size];
1723 assert_eq!(self.io().read_at(0, &mut read_buf[..]), read_buf.len());
1724 for (idx, byte) in read_buf.iter().enumerate() {
1725 if idx < offset {
1726 assert_eq!(*byte, SENTINEL_BYTE);
1727 } else if idx == offset {
1728 assert_eq!(*byte, WRITE_BYTE);
1729 } else {
1730 assert_eq!(*byte, PAD_BYTE);
1731 }
1732 }
1733 }
1734 }
1735
1736 impl<K, I, T> PartialEq<T> for Chained<DescId<K>>
1737 where
1738 K: AllocKind,
1739 I: ExactSizeIterator<Item = u16>,
1740 T: Copy + IntoIterator<IntoIter = I>,
1741 {
1742 fn eq(&self, other: &T) -> bool {
1743 let iter = other.into_iter();
1744 if usize::from(self.len) != iter.len() {
1745 return false;
1746 }
1747 self.iter().zip(iter).all(|(l, r)| l.get() == r)
1748 }
1749 }
1750
1751 impl Debug for TxAllocReq {
1752 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1753 let TxAllocReq { sender: _, size } = self;
1754 f.debug_struct("TxAllocReq").field("size", &size).finish_non_exhaustive()
1755 }
1756 }
1757
1758 #[test]
1759 fn alloc_tx_distinct() {
1760 let pool = Pool::new_test_default();
1761 let allocated = pool.alloc_tx_all(1);
1762 assert_eq!(allocated.len(), DEFAULT_TX_BUFFERS.get().into());
1763 let distinct = allocated
1764 .iter()
1765 .map(|alloc| {
1766 assert_eq!(alloc.descs.len(), 1);
1767 alloc.descs[0].get()
1768 })
1769 .collect::<HashSet<u16>>();
1770 assert_eq!(allocated.len(), distinct.len());
1771 }
1772
1773 #[test]
1774 fn alloc_tx_free_len() {
1775 let pool = Pool::new_test_default();
1776 {
1777 let allocated = pool.alloc_tx_all(2);
1778 assert_eq!(
1779 allocated.iter().fold(0, |acc, a| { acc + a.descs.len() }),
1780 DEFAULT_TX_BUFFERS.get().into()
1781 );
1782 assert_eq!(pool.tx_alloc_state_lock().free_lists[0].free, 0);
1783 }
1784 assert_eq!(pool.tx_alloc_state_lock().free_lists[0].free, DEFAULT_TX_BUFFERS.get());
1785 }
1786
1787 #[test]
1788 fn alloc_tx_chain() {
1789 let pool = Pool::new_test_default();
1790 let allocated = pool.alloc_tx_all(3);
1791 assert_eq!(allocated.len(), usize::from(DEFAULT_TX_BUFFERS.get()) / 3);
1792 assert_matches!(pool.alloc_tx_now_or_never(3), None);
1793 assert_matches!(pool.alloc_tx_now_or_never(2), Some(a) if a.descs.len() == 2);
1794 }
1795
1796 #[test]
1797 fn alloc_tx_many() {
1798 let pool = Pool::new_test_default();
1799 let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1800 - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
1801 - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
1802 let data_len = usize::try_from(data_len).unwrap();
1803 let mut buffers = pool
1804 .alloc_tx_buffers(data_len)
1805 .now_or_never()
1806 .expect("failed to alloc")
1807 .unwrap()
1808 .collect::<Result<Vec<_>>>()
1811 .expect("buffer error");
1812 assert_eq!(buffers.len(), DEFAULT_TX_BUFFERS.get().into());
1813
1814 assert!(pool.alloc_tx_buffers(data_len).now_or_never().is_none());
1817
1818 assert_matches!(buffers.pop(), Some(_));
1820 let mut more_buffers =
1821 pool.alloc_tx_buffers(data_len).now_or_never().expect("failed to alloc").unwrap();
1822 let buffer = assert_matches!(more_buffers.next(), Some(Ok(b)) => b);
1823 assert_matches!(more_buffers.next(), None);
1824 drop(buffer);
1827 assert_matches!(more_buffers.next(), None);
1828 }
1829
1830 #[test]
1831 fn alloc_tx_after_free() {
1832 let pool = Pool::new_test_default();
1833 let mut allocated = pool.alloc_tx_all(1);
1834 assert_matches!(pool.alloc_tx_now_or_never(2), None);
1835 {
1836 let _drained = allocated.drain(..2);
1837 }
1838 assert_matches!(pool.alloc_tx_now_or_never(2), Some(a) if a.descs.len() == 2);
1839 }
1840
1841 #[test]
1842 fn blocking_alloc_tx() {
1843 let mut executor = fasync::TestExecutor::new();
1844 let pool = Pool::new_test_default();
1845 let mut allocated = pool.alloc_tx_all(1);
1846 let alloc_fut = pool.alloc_tx_checked(1);
1847 let mut alloc_fut = pin!(alloc_fut);
1848 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1850 assert!(!pool.tx_alloc_state_lock().requests.is_empty());
1852 let freed = allocated
1853 .pop()
1854 .expect("no fulfulled allocations")
1855 .iter()
1856 .map(|x| x.get())
1857 .collect::<Chained<_>>();
1858 let same_as_freed =
1859 |descs: &Chained<DescId<Tx>>| descs.iter().map(|x| x.get()).eq(freed.iter().copied());
1860 assert_matches!(
1862 &executor.run_until_stalled(&mut alloc_fut),
1863 Poll::Ready(AllocGuard{ descs, pool: _ }) if same_as_freed(descs)
1864 );
1865 assert!(pool.tx_alloc_state_lock().requests.is_empty());
1867 }
1868
1869 #[test]
1870 fn blocking_alloc_tx_cancel_before_free() {
1871 let mut executor = fasync::TestExecutor::new();
1872 let pool = Pool::new_test_default();
1873 let mut allocated = pool.alloc_tx_all(1);
1874 {
1875 let alloc_fut = pool.alloc_tx_checked(1);
1876 let mut alloc_fut = pin!(alloc_fut);
1877 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1878 assert_matches!(
1879 pool.tx_alloc_state_lock().requests.as_slices(),
1880 (&[ref req1, ref req2], &[]) if req1.size.get() == 1 && req2.size.get() == 1
1881 );
1882 }
1883 assert_matches!(
1884 allocated.pop(),
1885 Some(AllocGuard { ref descs, pool: ref p })
1886 if descs == &[DEFAULT_TX_BUFFERS.get() - 1] && Arc::ptr_eq(p, &pool)
1887 );
1888 let state = pool.tx_alloc_state_lock();
1889 assert_eq!(state.free_lists[0].free, 1);
1890 assert!(state.requests.is_empty());
1891 }
1892
1893 #[test]
1894 fn blocking_alloc_tx_cancel_after_free() {
1895 let mut executor = fasync::TestExecutor::new();
1896 let pool = Pool::new_test_default();
1897 let mut allocated = pool.alloc_tx_all(1);
1898 {
1899 let alloc_fut = pool.alloc_tx_checked(1);
1900 let mut alloc_fut = pin!(alloc_fut);
1901 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1902 assert_matches!(
1903 pool.tx_alloc_state_lock().requests.as_slices(),
1904 (&[ref req1, ref req2], &[]) if req1.size.get() == 1 && req2.size.get() == 1
1905 );
1906 assert_matches!(
1907 allocated.pop(),
1908 Some(AllocGuard { ref descs, pool: ref p })
1909 if descs == &[DEFAULT_TX_BUFFERS.get() - 1] && Arc::ptr_eq(p, &pool)
1910 );
1911 }
1912 let state = pool.tx_alloc_state_lock();
1913 assert_eq!(state.free_lists[0].free, 1);
1914 assert!(state.requests.is_empty());
1915 }
1916
1917 #[test]
1918 fn multiple_blocking_alloc_tx_fulfill_order() {
1919 const TASKS_TOTAL: usize = 3;
1920 let mut executor = fasync::TestExecutor::new();
1921 let pool = Pool::new_test_default();
1922 let mut allocated = pool.alloc_tx_all(1);
1923 let mut alloc_futs = (1..=TASKS_TOTAL)
1924 .rev()
1925 .map(|x| {
1926 let pool = pool.clone();
1927 (x, Box::pin(async move { pool.alloc_tx_checked(x.try_into().unwrap()).await }))
1928 })
1929 .collect::<Vec<_>>();
1930
1931 for (idx, (req_size, task)) in alloc_futs.iter_mut().enumerate() {
1932 assert_matches!(executor.run_until_stalled(task), Poll::Pending);
1933 assert_eq!(idx + *req_size, TASKS_TOTAL);
1935 }
1936 {
1937 let state = pool.tx_alloc_state_lock();
1938 assert_eq!(state.requests.len(), TASKS_TOTAL + 1);
1940 let mut requests = state.requests.iter();
1941 assert!(requests.next().unwrap().sender.is_canceled());
1944 assert!(requests.all(|req| !req.sender.is_canceled()))
1946 }
1947
1948 let mut to_free = Vec::new();
1949 let mut freed = 0;
1950 for free_size in (1..=TASKS_TOTAL).rev() {
1951 let (_req_size, mut task) = alloc_futs.remove(0);
1952 for _ in 1..free_size {
1953 freed += 1;
1954 assert_matches!(
1955 allocated.pop(),
1956 Some(AllocGuard { ref descs, pool: ref p })
1957 if descs == &[DEFAULT_TX_BUFFERS.get() - freed] && Arc::ptr_eq(p, &pool)
1958 );
1959 assert_matches!(executor.run_until_stalled(&mut task), Poll::Pending);
1960 }
1961 freed += 1;
1962 assert_matches!(
1963 allocated.pop(),
1964 Some(AllocGuard { ref descs, pool: ref p })
1965 if descs == &[DEFAULT_TX_BUFFERS.get() - freed] && Arc::ptr_eq(p, &pool)
1966 );
1967 match executor.run_until_stalled(&mut task) {
1968 Poll::Ready(alloc) => {
1969 assert_eq!(alloc.len(), free_size);
1970 to_free.push(alloc);
1972 }
1973 Poll::Pending => panic!("The request should be fulfilled"),
1974 }
1975 for (_req_size, task) in alloc_futs.iter_mut() {
1977 assert_matches!(executor.run_until_stalled(task), Poll::Pending);
1978 }
1979 }
1980 assert!(pool.tx_alloc_state_lock().requests.is_empty());
1981 }
1982
1983 #[test]
1984 fn singleton_tx_layout() {
1985 let pool = Pool::new_test_default();
1986 let buffers = std::iter::from_fn(|| {
1987 let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1988 - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
1989 - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
1990 pool.alloc_tx_buffer_now_or_never(usize::try_from(data_len).unwrap()).map(|buffer| {
1991 assert_eq!(buffer.alloc.descriptors().count(), 1);
1992 let offset = u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1993 * u64::from(buffer.alloc[0].get());
1994 {
1995 let descriptor = buffer.alloc.descriptor();
1996 assert_matches!(descriptor.chain_length(), Ok(ChainLength::ZERO));
1997 assert_eq!(descriptor.head_length(), DEFAULT_MIN_TX_BUFFER_HEAD);
1998 assert_eq!(descriptor.tail_length(), DEFAULT_MIN_TX_BUFFER_TAIL);
1999 assert_eq!(descriptor.data_length(), data_len);
2000 assert_eq!(descriptor.offset(), offset);
2001 }
2002
2003 {
2004 let mut slices = buffer.parts();
2005 let slice = slices.next().expect("should have one slice");
2006 assert_matches!(slices.next(), None);
2007 assert_eq!(slice.len(), usize::try_from(data_len).unwrap());
2008 assert_eq!(
2009 slice.as_ptr(),
2010 pool.base.as_ptr().wrapping_add(
2011 usize::try_from(offset).unwrap()
2012 + usize::from(DEFAULT_MIN_TX_BUFFER_HEAD),
2013 )
2014 );
2015 }
2016 buffer
2017 })
2018 })
2019 .collect::<Vec<_>>();
2020 assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()));
2021 }
2022
2023 #[test]
2024 fn chained_tx_layout() {
2025 let pool = Pool::new_test_default();
2026 let alloc_len = 4 * DEFAULT_BUFFER_LENGTH.get()
2027 - usize::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2028 - usize::from(DEFAULT_MIN_TX_BUFFER_TAIL);
2029 let buffers = std::iter::from_fn(|| {
2030 pool.alloc_tx_buffer_now_or_never(alloc_len).map(|buffer| {
2031 assert_eq!(buffer.parts().count(), 4);
2032 for (idx, (descriptor, slice)) in
2033 buffer.alloc.descriptors().zip(buffer.parts()).enumerate()
2034 {
2035 let chain_length = ChainLength::try_from(buffer.alloc.len() - idx - 1).unwrap();
2036 let head_length = if idx == 0 { DEFAULT_MIN_TX_BUFFER_HEAD } else { 0 };
2037 let tail_length = if chain_length == ChainLength::ZERO {
2038 DEFAULT_MIN_TX_BUFFER_TAIL
2039 } else {
2040 0
2041 };
2042 let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2043 - u32::from(head_length)
2044 - u32::from(tail_length);
2045 let offset = u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2046 * u64::from(buffer.alloc[idx].get());
2047 assert_eq!(descriptor.chain_length().unwrap(), chain_length);
2048 assert_eq!(descriptor.head_length(), head_length);
2049 assert_eq!(descriptor.tail_length(), tail_length);
2050 assert_eq!(descriptor.offset(), offset);
2051 assert_eq!(descriptor.data_length(), data_len);
2052 if chain_length != ChainLength::ZERO {
2053 assert_eq!(descriptor.nxt(), Some(buffer.alloc[idx + 1].get()));
2054 }
2055
2056 assert_eq!(slice.len(), usize::try_from(data_len).unwrap());
2057 assert_eq!(
2058 slice.as_ptr(),
2059 pool.base.as_ptr().wrapping_add(
2060 usize::try_from(offset).unwrap() + usize::from(head_length),
2061 )
2062 );
2063 }
2064 buffer
2065 })
2066 })
2067 .collect::<Vec<_>>();
2068 assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()) / 4);
2069 }
2070
2071 #[test]
2072 fn rx_distinct() {
2073 let pool = Pool::new_test_default();
2074 let mut guard = pool.rx_pending.lock();
2075 let descs = &mut guard.storage;
2076 assert_eq!(descs.len(), usize::from(DEFAULT_RX_BUFFERS.get()));
2077 let distinct = descs.iter().map(|desc| desc.get()).collect::<HashSet<u16>>();
2078 assert_eq!(descs.len(), distinct.len());
2079 }
2080
2081 #[test]
2082 fn alloc_rx_layout() {
2083 let pool = Pool::new_test_default();
2084 let mut guard = pool.rx_pending.lock();
2085 let descs = &mut guard.storage;
2086 assert_eq!(descs.len(), usize::from(DEFAULT_RX_BUFFERS.get()));
2087 for desc in descs.iter() {
2088 let descriptor = pool.descriptors.borrow(desc);
2089 let offset =
2090 u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap() * u64::from(desc.get());
2091 assert_matches!(descriptor.chain_length(), Ok(ChainLength::ZERO));
2092 assert_eq!(descriptor.head_length(), 0);
2093 assert_eq!(descriptor.tail_length(), 0);
2094 assert_eq!(descriptor.offset(), offset);
2095 assert_eq!(
2096 descriptor.data_length(),
2097 u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2098 );
2099 }
2100 }
2101
2102 #[test]
2103 fn buffer_read_at_write_at() {
2104 let pool = Pool::new_test_default();
2105 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2106 let mut buffer =
2107 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2108 assert_eq!(buffer.parts().count(), 2);
2111 assert_eq!(buffer.len(), alloc_bytes);
2112 let write_buf = (0..u8::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()).collect::<Vec<_>>();
2113 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), write_buf.len());
2114 let mut read_buf = [0xff; DEFAULT_BUFFER_LENGTH.get()];
2115 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), read_buf.len());
2116 for (idx, byte) in read_buf.iter().enumerate() {
2117 assert_eq!(*byte, write_buf[idx]);
2118 }
2119 }
2120
2121 #[test]
2122 fn buffer_write_at_short() {
2123 let pool = Pool::new_test_default();
2124 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2125 let mut buffer =
2126 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2127 assert_eq!(buffer.parts().count(), 2);
2128 assert_eq!(buffer.len(), alloc_bytes);
2129
2130 let write_buf = vec![WRITE_BYTE; alloc_bytes + 10];
2131
2132 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2134
2135 let mut read_buf = vec![0; alloc_bytes];
2137 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2138 for byte in read_buf.iter() {
2139 assert_eq!(*byte, WRITE_BYTE);
2140 }
2141
2142 assert_eq!(buffer.io_mut().write_at(alloc_bytes + 1, &write_buf[..]), 0);
2144
2145 let offset = alloc_bytes / 2;
2147 let expected_write = alloc_bytes - offset;
2148 let write_buf = vec![2; alloc_bytes]; assert_eq!(buffer.io_mut().write_at(offset, &write_buf[..]), expected_write);
2150
2151 let mut read_buf = vec![0; alloc_bytes];
2153 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2154 for (idx, byte) in read_buf.iter().enumerate() {
2155 if idx < offset {
2156 assert_eq!(*byte, WRITE_BYTE);
2157 } else {
2158 assert_eq!(*byte, 2);
2159 }
2160 }
2161 }
2162
2163 #[test]
2164 fn buffer_read_at_short() {
2165 let pool = Pool::new_test_default();
2166 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2167 let mut buffer =
2168 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2169 assert_eq!(buffer.parts().count(), 2);
2170 assert_eq!(buffer.len(), alloc_bytes);
2171
2172 let write_buf = vec![WRITE_BYTE; alloc_bytes];
2173 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2174
2175 let mut read_buf = vec![0xff; alloc_bytes + 10];
2177 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2178 for (idx, byte) in read_buf.iter().enumerate() {
2179 if idx < alloc_bytes {
2180 assert_eq!(*byte, WRITE_BYTE);
2181 } else {
2182 assert_eq!(*byte, 0xff);
2183 }
2184 }
2185
2186 assert_eq!(buffer.io().read_at(alloc_bytes + 1, &mut read_buf[..]), 0);
2188
2189 let offset = alloc_bytes / 2;
2191 let expected_read = alloc_bytes - offset;
2192 let mut read_buf = vec![0xff; alloc_bytes];
2193 assert_eq!(buffer.io().read_at(offset, &mut read_buf[..]), expected_read);
2194 for (idx, byte) in read_buf.iter().enumerate() {
2195 if idx < expected_read {
2196 assert_eq!(*byte, WRITE_BYTE);
2197 } else {
2198 assert_eq!(*byte, 0xff);
2199 }
2200 }
2201 }
2202
2203 #[test]
2204 fn buffer_read_write_seek() {
2205 let pool = Pool::new_test_default();
2206 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2207 let mut buffer =
2208 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2209 assert_eq!(buffer.parts().count(), 2);
2212 assert_eq!(buffer.len(), alloc_bytes);
2213 let write_buf = (0..u8::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()).collect::<Vec<_>>();
2214
2215 let mut io = buffer.io_mut();
2216
2217 assert_eq!(io.write(&write_buf[..]).expect("failed to write into buffer"), write_buf.len());
2218 const SEEK_FROM_END: usize = 64;
2219 const READ_LEN: usize = 12;
2220 assert_eq!(
2221 io.seek(SeekFrom::End(-i64::try_from(SEEK_FROM_END).unwrap())).unwrap(),
2222 u64::try_from(io.len - SEEK_FROM_END).unwrap()
2223 );
2224 let mut read_buf = [0xff; READ_LEN];
2225 assert_eq!(io.read(&mut read_buf[..]).expect("failed to read from buffer"), read_buf.len());
2226 assert_eq!(&write_buf[..READ_LEN], &read_buf[..]);
2227 }
2228
2229 #[test_case(32; "single buffer part")]
2230 #[test_case(MAX_BUFFER_BYTES; "multiple buffer parts")]
2231 fn buffer_pad(pad_size: usize) {
2232 let mut pool = Pool::new_test_default();
2233 pool.set_min_tx_buffer_length(pad_size);
2234 for offset in 0..pad_size {
2235 Arc::get_mut(&mut pool)
2236 .expect("there are multiple owners of the underlying VMO")
2237 .fill_sentinel_bytes();
2238 let mut buffer =
2239 pool.alloc_tx_buffer_now_or_never(offset + 1).expect("failed to allocate buffer");
2240 buffer.check_write_and_pad(offset, pad_size);
2241 }
2242 }
2243
2244 #[test]
2245 fn buffer_pad_grow() {
2246 const BUFFER_PARTS: u8 = 3;
2247 let mut pool = Pool::new_test_default();
2248 let pad_size = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2249 * u32::from(BUFFER_PARTS)
2250 - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2251 - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
2252 pool.set_min_tx_buffer_length(pad_size.try_into().unwrap());
2253 for offset in 0..pad_size - u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap() {
2254 Arc::get_mut(&mut pool)
2255 .expect("there are multiple owners of the underlying VMO")
2256 .fill_sentinel_bytes();
2257 let mut alloc =
2258 pool.alloc_tx_now_or_never(BUFFER_PARTS).expect("failed to alloc descriptors");
2259 alloc
2260 .init(usize::try_from(offset).unwrap() + 1)
2261 .expect("head/body/tail sizes are representable with u16/u32/u16");
2262 let mut buffer = Buffer::try_from(alloc).unwrap();
2263 buffer.check_write_and_pad(offset.try_into().unwrap(), pad_size.try_into().unwrap());
2264 }
2265 }
2266
2267 #[test_case( 0; "writes at the beginning")]
2268 #[test_case( 15; "writes in the first part")]
2269 #[test_case( 75; "writes in the second part")]
2270 #[test_case(135; "writes in the third part")]
2271 #[test_case(195; "writes in the last part")]
2272 fn buffer_used(write_offset: usize) {
2273 let pool = Pool::new_test_default();
2274 let mut buffer =
2275 pool.alloc_tx_buffer_now_or_never(MAX_BUFFER_BYTES).expect("failed to allocate buffer");
2276 let expected_caps = (0..netdev::MAX_DESCRIPTOR_CHAIN).map(|i| {
2277 if i == 0 {
2278 DEFAULT_BUFFER_LENGTH.get() - usize::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2279 } else if i < netdev::MAX_DESCRIPTOR_CHAIN - 1 {
2280 DEFAULT_BUFFER_LENGTH.get()
2281 } else {
2282 DEFAULT_BUFFER_LENGTH.get() - usize::from(DEFAULT_MIN_TX_BUFFER_TAIL)
2283 }
2284 });
2285 assert_eq!(buffer.alloc.len(), netdev::MAX_DESCRIPTOR_CHAIN.into());
2286 assert_eq!(buffer.io_mut().write_at(write_offset, &[WRITE_BYTE][..]), 1);
2287 assert_eq!(
2290 buffer.parts().zip(expected_caps).fold(
2291 Some(write_offset),
2292 |offset, (slice, expected_cap)| {
2293 assert_eq!(slice.len(), expected_cap);
2294 match offset {
2295 Some(offset) => {
2296 if offset >= expected_cap {
2297 Some(offset - slice.len())
2298 } else {
2299 assert_eq!(slice[offset], WRITE_BYTE);
2300 None
2301 }
2302 }
2303 None => None,
2304 }
2305 }
2306 ),
2307 None
2308 );
2309 }
2310
2311 #[test]
2312 fn allocate_under_device_minimum() {
2313 const MIN_TX_DATA: usize = 32;
2314 const ALLOC_SIZE: usize = 16;
2315 const WRITE_BYTE: u8 = 0xff;
2316 const WRITE_SENTINAL_BYTE: u8 = 0xee;
2317 const READ_SENTINAL_BYTE: u8 = 0xdd;
2318 let mut config = default_config();
2319 config.buffer_layout.min_tx_data = MIN_TX_DATA;
2320 let (pool, _descriptors, _vmo) = Pool::new_test_pool(config);
2321 for mut buffer in Vec::from_iter(std::iter::from_fn({
2322 let pool = pool.clone();
2323 move || pool.alloc_tx_buffer_now_or_never(MIN_TX_DATA)
2324 })) {
2325 assert_eq!(
2326 buffer.io_mut().write_at(0, &[WRITE_SENTINAL_BYTE; MIN_TX_DATA]),
2327 MIN_TX_DATA
2328 );
2329 }
2330 let mut allocated =
2331 pool.alloc_tx_buffer_now_or_never(16).expect("failed to allocate buffer");
2332 assert_eq!(allocated.len(), MIN_TX_DATA);
2333 const WRITE_BUF_SIZE: usize = MIN_TX_DATA + 1;
2334 assert_eq!(allocated.io_mut().write_at(0, &[WRITE_BYTE; WRITE_BUF_SIZE]), MIN_TX_DATA);
2335 assert_eq!(allocated.io_mut().write_at(0, &[WRITE_BYTE; ALLOC_SIZE]), ALLOC_SIZE);
2336 assert_eq!(allocated.len(), MIN_TX_DATA);
2337 const READ_BUF_SIZE: usize = MIN_TX_DATA + 1;
2338 let mut read_buf = [READ_SENTINAL_BYTE; READ_BUF_SIZE];
2339 assert_eq!(allocated.io().read_at(0, &mut read_buf[..]), MIN_TX_DATA);
2340 assert_eq!(allocated.io().read_at(0, &mut read_buf[..MIN_TX_DATA]), MIN_TX_DATA);
2341 assert_eq!(&read_buf[..ALLOC_SIZE], &[WRITE_BYTE; ALLOC_SIZE][..]);
2342 assert_eq!(&read_buf[ALLOC_SIZE..MIN_TX_DATA], &[WRITE_BYTE; ALLOC_SIZE][..]);
2343 assert_eq!(&read_buf[MIN_TX_DATA..], &[READ_SENTINAL_BYTE; 1][..]);
2344 }
2345
2346 #[test]
2347 fn invalid_tx_length() {
2348 let mut config = default_config();
2349 config.buffer_layout.length = usize::from(u16::MAX) + 2;
2350 config.buffer_layout.min_tx_head = 0;
2351 let (pool, _descriptors, _vmo) = Pool::new_test_pool(config);
2352 assert_matches!(pool.alloc_tx_buffer(1).now_or_never(), Some(Err(Error::TxLength)));
2353 }
2354
2355 #[test]
2356 fn vmo_indices_tracking() {
2357 let mut config = default_config();
2358 config.tx_vmos = vec![
2359 TxVmoConfig { vmo_id: 0, num_buffers: 2 },
2360 TxVmoConfig { vmo_id: 1, num_buffers: 4 },
2361 ];
2362
2363 let (pool, _descriptors, _vmos) = Pool::new_test_pool(config);
2364
2365 {
2368 let state = pool.tx_alloc_state_lock();
2369 assert_eq!(state.first_available_index, 0);
2370 }
2371
2372 let alloc1 = pool.alloc_tx_now_or_never(1).expect("alloc 1");
2374 {
2375 let state = pool.tx_alloc_state_lock();
2376 assert_eq!(state.first_available_index, 0);
2378 }
2379
2380 let alloc2 = pool.alloc_tx_now_or_never(1).expect("alloc 2");
2382 {
2383 let state = pool.tx_alloc_state_lock();
2384 assert_eq!(state.first_available_index, 1);
2386 }
2387
2388 let alloc3 = pool.alloc_tx_now_or_never(1).expect("alloc 3");
2390 {
2391 let state = pool.tx_alloc_state_lock();
2392 assert_eq!(state.first_available_index, 1);
2394 }
2395
2396 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 drop(alloc1);
2407 {
2408 let state = pool.tx_alloc_state_lock();
2409 assert_eq!(state.first_available_index, 0);
2411 }
2412
2413 drop(alloc3);
2415 {
2416 let state = pool.tx_alloc_state_lock();
2417 assert_eq!(state.first_available_index, 0);
2419 }
2420
2421 drop(alloc2);
2423 {
2424 let state = pool.tx_alloc_state_lock();
2425 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 let counter_before = state.rx_frame_counter.load(atomic::Ordering::SeqCst);
2460 {
2461 let mut fut = pin!(watcher.wait_until(10000));
2462 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2463 }
2464 let counter_after = state.rx_frame_counter.load(atomic::Ordering::SeqCst);
2465 assert_eq!(counter_before, counter_after);
2466 }
2467
2468 #[test]
2469 #[should_panic(expected = "slice end")]
2470 fn get_slice_out_of_bounds_panic() {
2471 let mut config = default_config();
2472 config.buffer_layout.length = 64;
2473 config.buffer_stride = NonZeroU64::new(64).unwrap();
2474 config.tx_vmos = vec![TxVmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: 1 }];
2475 config.num_rx_buffers = NonZeroU16::new(1).unwrap();
2476
2477 let (mut pool, _descriptors_vmo, _data_vmos) = Pool::new_test_pool(config);
2478 Arc::get_mut(&mut pool)
2479 .expect("there are multiple owners of the underlying VMO")
2480 .fill_sentinel_bytes();
2481
2482 let mut buffer = pool.alloc_tx_buffer_now_or_never(10).expect("failed to alloc buffer");
2483 {
2484 let mut desc = buffer.alloc.descriptor_mut();
2485 desc.set_data_length(4093);
2486 }
2487 let _slice = buffer.as_slice_mut();
2488 }
2489}