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_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 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 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 receiver.await.unwrap()
359 }
360
361 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 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 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()
433 .map(move |mut alloc| {
434 alloc.init(num_bytes)?;
435 Ok(alloc.into())
436 });
437 Ok(iter)
438 }
439
440 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 fn free_tx(self: &Arc<Self>, chain: Chained<DescId<Tx>>) {
459 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 while let Some(req) = state.requests.front() {
491 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 let req = state.requests.pop_front().unwrap();
504 to_fulfill.push((req, AllocGuard::new(descs, self.clone())));
505
506 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 drop(state);
523 for (req, alloc) in to_fulfill {
525 req.fulfill(alloc)
526 }
527 }
528
529 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 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 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 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 0
632 } else {
633 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 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 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
685pub struct Buffer<K: AllocKind> {
687 alloc: AllocGuard<K>,
689}
690
691impl<K: AllocKind> Buffer<K> {
692 pub(in crate::session) fn vmo_id(&self) -> u8 {
693 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 pub fn len(&self) -> usize {
700 self.parts().map(|s| s.len()).sum()
701 }
702
703 fn parts(&self) -> impl Iterator<Item = &[u8]> + '_ {
705 self.alloc.descs.iter().map(|desc| self.alloc.pool.get_slice(desc))
706 }
707
708 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 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 pub fn as_slice(&self) -> Option<&[u8]> {
721 if self.alloc.len() != 1 {
722 return None;
723 }
724 self.parts().next()
725 }
726
727 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 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 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
750pub struct TxMetadataMut<'a> {
756 desc: DescRefMut<'a, Tx>,
757}
758
759impl<'a> TxMetadataMut<'a> {
760 pub fn set_port(&mut self, port: Port) {
762 self.desc.set_port(port);
763 }
764
765 pub fn set_frame_type(&mut self, frame_type: netdev::FrameType) {
767 self.desc.set_frame_type(frame_type);
768 }
769
770 pub fn set_tx_flags(&mut self, flags: netdev::TxFlags) {
772 self.desc.set_tx_flags(flags);
773 }
774
775 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 pub fn meta_mut(&mut self) -> TxMetadataMut<'_> {
784 TxMetadataMut { desc: self.alloc.descriptor_mut() }
785 }
786
787 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
817pub enum ChecksumRxOffloading {
819 Offloaded(NonZeroU16),
821}
822
823pub struct RxMetadata<'a> {
829 desc: DescRef<'a, Rx>,
830}
831
832impl<'a> RxMetadata<'a> {
833 pub fn rx_flags(&self) -> Result<netdev::RxFlags> {
835 self.desc.rx_flags()
836 }
837
838 pub fn rx_checksum_offloading(&self) -> Option<ChecksumRxOffloading> {
840 self.desc.rx_checksum_offloading()
841 }
842
843 pub fn frame_type(&self) -> Result<netdev::FrameType> {
845 self.desc.frame_type()
846 }
847
848 pub fn port(&self) -> Port {
850 self.desc.port()
851 }
852}
853
854impl Buffer<Rx> {
855 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
868pub struct SinglePartTxBuffer(Buffer<Tx>);
871
872impl SinglePartTxBuffer {
873 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 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 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 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
924pub 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 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 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
1011struct 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 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 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 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 Self { storage: unsafe { MaybeUninit::uninit().assume_init() }, len: ChainLength::ZERO }
1058 }
1059}
1060
1061impl<T> FromIterator<T> for Chained<T> {
1062 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 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 #[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 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 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
1145pub(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 fn descriptors(&self) -> impl Iterator<Item = DescRef<'_, K>> + '_ {
1165 self.descs.iter().map(move |desc| self.pool.descriptors.borrow(desc))
1166 }
1167
1168 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 fn descriptor(&self) -> DescRef<'_, K> {
1176 self.descriptors().next().expect("descriptors must not be empty")
1177 }
1178
1179 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 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 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 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 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 {
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 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
1382struct 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 fn fulfill(self, guard: AllocGuard<Tx>) {
1402 let Self { sender, size: _ } = self;
1403 match sender.send(guard) {
1404 Ok(()) => (),
1405 Err(guard) => {
1406 drop(guard);
1409 }
1410 }
1411 }
1412}
1413
1414mod 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 pub struct Allocation<'a, K: AllocKind>(pub(super) &'a mut super::AllocGuard<K>);
1426}
1427
1428pub trait AllocKind: private::Sealed {
1431 const REFL: AllocKindRefl;
1433
1434 fn free(alloc: private::Allocation<'_, Self>);
1436}
1437
1438pub enum Tx {}
1440pub enum Rx {}
1442
1443pub 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
1477pub(in crate::session) struct RxLeaseHandlingState {
1479 can_watch_rx_leases: AtomicBool,
1480 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 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 if prev == u64::MAX {
1515 rx_lease_waker.wake();
1516 }
1517 }
1518}
1519
1520pub(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
1538pub(in crate::session) struct RxLeaseWatcher<T> {
1540 state: T,
1541}
1542
1543impl<T: RxLeaseHandlingStateContainer> RxLeaseWatcher<T> {
1544 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 pub(in crate::session) async fn wait_until(&mut self, hold_until_frame: u64) {
1567 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 let _guard = scopeguard::guard((), |()| {
1582 let _: u64 = rx_frame_counter.fetch_add(hold_until_frame, atomic::Ordering::SeqCst);
1583 });
1584
1585 if prev >= hold_until_frame {
1587 return;
1588 }
1589 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 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 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 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 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::<Result<Vec<_>>>()
1812 .expect("buffer error");
1813 assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()));
1814
1815 assert!(pool.alloc_tx_buffers(data_len).now_or_never().is_none());
1818
1819 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 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 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1851 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 assert_matches!(
1863 &executor.run_until_stalled(&mut alloc_fut),
1864 Poll::Ready(AllocGuard{ descs, pool: _ }) if same_as_freed(descs)
1865 );
1866 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_eq!(idx + *req_size, TASKS_TOTAL);
1936 }
1937 {
1938 let state = pool.tx_alloc_state_lock();
1939 assert_eq!(state.requests.len(), TASKS_TOTAL + 1);
1941 let mut requests = state.requests.iter();
1942 assert!(requests.next().unwrap().sender.is_canceled());
1945 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 to_free.push(alloc);
1973 }
1974 Poll::Pending => panic!("The request should be fulfilled"),
1975 }
1976 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 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 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2135
2136 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 assert_eq!(buffer.io_mut().write_at(alloc_bytes + 1, &write_buf[..]), 0);
2145
2146 let offset = alloc_bytes / 2;
2148 let expected_write = alloc_bytes - offset;
2149 let write_buf = vec![2; alloc_bytes]; assert_eq!(buffer.io_mut().write_at(offset, &write_buf[..]), expected_write);
2151
2152 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 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 assert_eq!(buffer.io().read_at(alloc_bytes + 1, &mut read_buf[..]), 0);
2189
2190 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 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 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 {
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![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}