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 fn empty() -> Self {
1050 Self {
1051 storage: [const { MaybeUninit::uninit() }; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1052 len: ChainLength::ZERO,
1053 }
1054 }
1055}
1056
1057impl<T> FromIterator<T> for Chained<T> {
1058 fn from_iter<I: IntoIterator<Item = T>>(elements: I) -> Self {
1062 let mut result = Self::empty();
1063 let mut len = 0u8;
1064 for (idx, e) in elements.into_iter().enumerate() {
1065 result.storage[idx] = MaybeUninit::new(e);
1066 len += 1;
1067 }
1068 result.len = ChainLength::try_from(len).unwrap();
1071 result
1072 }
1073}
1074
1075impl<T> IntoIterator for Chained<T> {
1076 type Item = T;
1077 type IntoIter = ChainedIter<T>;
1078
1079 fn into_iter(mut self) -> Self::IntoIter {
1080 let len = self.len;
1081 self.len = ChainLength::ZERO;
1082 let storage = std::mem::replace(
1083 &mut self.storage,
1084 [const { MaybeUninit::uninit() }; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1085 );
1086 ChainedIter { storage, len, consumed: 0 }
1087 }
1088}
1089
1090struct ChainedIter<T> {
1091 storage: [MaybeUninit<T>; netdev::MAX_DESCRIPTOR_CHAIN as usize],
1092 len: ChainLength,
1093 consumed: u8,
1094}
1095
1096impl<T> Iterator for ChainedIter<T> {
1097 type Item = T;
1098
1099 fn next(&mut self) -> Option<Self::Item> {
1100 if self.consumed < self.len.get() {
1101 let value = unsafe {
1104 std::mem::replace(
1105 &mut self.storage[usize::from(self.consumed)],
1106 MaybeUninit::uninit(),
1107 )
1108 .assume_init()
1109 };
1110 self.consumed += 1;
1111 Some(value)
1112 } else {
1113 None
1114 }
1115 }
1116
1117 fn size_hint(&self) -> (usize, Option<usize>) {
1118 let len = usize::from(self.len.get() - self.consumed);
1119 (len, Some(len))
1120 }
1121}
1122
1123impl<T> ExactSizeIterator for ChainedIter<T> {}
1124
1125impl<T> Drop for ChainedIter<T> {
1126 fn drop(&mut self) {
1127 unsafe {
1129 std::ptr::drop_in_place(std::mem::transmute::<_, &mut [T]>(
1130 &mut self.storage[self.consumed.into()..self.len.into()],
1131 ));
1132 }
1133 }
1134}
1135
1136pub(in crate::session) struct AllocGuard<K: AllocKind> {
1138 descs: Chained<DescId<K>>,
1139 pool: Arc<Pool>,
1140}
1141
1142impl<K: AllocKind> Debug for AllocGuard<K> {
1143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1144 let Self { descs, pool: _ } = self;
1145 f.debug_struct("AllocGuard").field("descs", descs).finish()
1146 }
1147}
1148
1149impl<K: AllocKind> AllocGuard<K> {
1150 fn new(descs: Chained<DescId<K>>, pool: Arc<Pool>) -> Self {
1151 Self { descs, pool }
1152 }
1153
1154 fn descriptors(&self) -> impl Iterator<Item = DescRef<'_, K>> + '_ {
1156 self.descs.iter().map(move |desc| self.pool.descriptors.borrow(desc))
1157 }
1158
1159 fn descriptors_mut(&mut self) -> impl Iterator<Item = DescRefMut<'_, K>> + '_ {
1161 let descriptors = &self.pool.descriptors;
1162 self.descs.iter_mut().map(move |desc| descriptors.borrow_mut(desc))
1163 }
1164
1165 fn descriptor(&self) -> DescRef<'_, K> {
1167 self.descriptors().next().expect("descriptors must not be empty")
1168 }
1169
1170 fn descriptor_mut(&mut self) -> DescRefMut<'_, K> {
1172 self.descriptors_mut().next().expect("descriptors must not be empty")
1173 }
1174}
1175
1176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1177struct DescriptorLayout {
1178 chain_length: ChainLength,
1179 head_length: u16,
1180 data_length: u32,
1181 tail_length: u16,
1182}
1183
1184impl AllocGuard<Tx> {
1185 fn calculate_descriptor_layouts(&self, target_len: usize) -> Result<Chained<DescriptorLayout>> {
1194 let len = self.len();
1195 let BufferLayout { min_tx_head, min_tx_tail, length: buffer_length, .. } =
1196 self.pool.buffer_layout;
1197
1198 let mut remaining_target = target_len;
1199 (0..len)
1200 .rev()
1201 .map(|clen| {
1202 let chain_length = ChainLength::try_from(clen).unwrap();
1203 let head_length = if clen + 1 == len { min_tx_head } else { 0 };
1204 let mut tail_length = if clen == 0 { min_tx_tail } else { 0 };
1205
1206 let available_bytes = u32::try_from(
1209 buffer_length - usize::from(head_length) - usize::from(tail_length),
1210 )
1211 .unwrap();
1212
1213 let data_length = match u32::try_from(remaining_target) {
1214 Ok(target) => {
1215 if target < available_bytes {
1216 let excess = available_bytes - target;
1220 tail_length = u16::try_from(excess)
1221 .ok_checked::<TryFromIntError>()
1222 .and_then(|tail_adjustment| {
1223 tail_length.checked_add(tail_adjustment)
1224 })
1225 .ok_or(Error::TxLength)?;
1226 }
1227 target.min(available_bytes)
1228 }
1229 Err(TryFromIntError { .. }) => available_bytes,
1230 };
1231
1232 let data_length_usize =
1233 usize::try_from(data_length).expect("u32 must fit in a usize");
1234 remaining_target = remaining_target.saturating_sub(data_length_usize);
1235
1236 Ok::<_, Error>(DescriptorLayout {
1237 chain_length,
1238 head_length,
1239 data_length,
1240 tail_length,
1241 })
1242 })
1243 .collect()
1244 }
1245
1246 fn init(&mut self, requested_bytes: usize) -> Result<()> {
1261 let min_tx_data = self.pool.buffer_layout.min_tx_data;
1262 let target_len = requested_bytes.max(usize::from(min_tx_data));
1263 let layouts = self.calculate_descriptor_layouts(target_len)?;
1264
1265 let mut remaining_requested = requested_bytes;
1266
1267 for (desc_id, DescriptorLayout { chain_length, head_length, data_length, tail_length }) in
1268 self.descs.iter_mut().zip(layouts)
1269 {
1270 {
1272 let mut descriptor = self.pool.descriptors.borrow_mut(desc_id);
1273 descriptor.initialize(chain_length, head_length, data_length, tail_length);
1274 }
1275
1276 let data_length_usize = usize::try_from(data_length).expect("u32 must fit in a usize");
1277 let requested_in_part = std::cmp::min(remaining_requested, data_length_usize);
1278 let pad_in_part = data_length_usize - requested_in_part;
1279
1280 if pad_in_part > 0 {
1292 let slice = self.pool.get_slice_mut(desc_id);
1293 slice[requested_in_part..requested_in_part + pad_in_part].fill(0);
1294 }
1295
1296 remaining_requested -= requested_in_part;
1297 }
1298 Ok(())
1299 }
1300}
1301
1302impl<K: AllocKind> Drop for AllocGuard<K> {
1303 fn drop(&mut self) {
1304 if self.is_empty() {
1305 return;
1306 }
1307 K::free(private::Allocation(self));
1308 }
1309}
1310
1311impl<K: AllocKind> Deref for AllocGuard<K> {
1312 type Target = [DescId<K>];
1313
1314 fn deref(&self) -> &Self::Target {
1315 self.descs.deref()
1316 }
1317}
1318
1319impl<K: AllocKind> From<AllocGuard<K>> for Buffer<K> {
1320 fn from(alloc: AllocGuard<K>) -> Self {
1321 Self { alloc }
1322 }
1323}
1324
1325impl<T, K: AllocKind> Read for BufferIO<T, K>
1326where
1327 T: AsRef<[u8]>,
1328{
1329 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1330 let read_len = self.read_at(self.pos, buf);
1331 self.pos += read_len;
1332 Ok(read_len)
1333 }
1334}
1335
1336impl<T> Write for BufferIO<T, Tx>
1337where
1338 T: AsMut<[u8]>,
1339{
1340 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1341 let write_len = self.write_at(self.pos, buf);
1342 self.pos += write_len;
1343 Ok(write_len)
1344 }
1345
1346 fn flush(&mut self) -> std::io::Result<()> {
1347 Ok(())
1348 }
1349}
1350
1351impl<T, K: AllocKind> Seek for BufferIO<T, K> {
1352 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
1353 let pos = match pos {
1354 SeekFrom::Start(offset) => offset,
1355 SeekFrom::End(offset) => {
1356 let end = i64::try_from(self.len).unwrap();
1357 u64::try_from(end.wrapping_add(offset)).unwrap()
1358 }
1359 SeekFrom::Current(offset) => {
1360 let current = i64::try_from(self.pos).map_err(|TryFromIntError { .. }| {
1361 std::io::Error::from(std::io::ErrorKind::InvalidInput)
1362 })?;
1363 u64::try_from(current.wrapping_add(offset)).unwrap()
1364 }
1365 };
1366 self.pos = usize::try_from(pos).map_err(|TryFromIntError { .. }| {
1367 std::io::Error::from(std::io::ErrorKind::InvalidInput)
1368 })?;
1369 Ok(pos)
1370 }
1371}
1372
1373struct TxAllocReq {
1375 sender: Sender<AllocGuard<Tx>>,
1376 size: ChainLength,
1377}
1378
1379impl TxAllocReq {
1380 fn new(size: ChainLength) -> (Self, Receiver<AllocGuard<Tx>>) {
1381 let (sender, receiver) = channel();
1382 (TxAllocReq { sender, size }, receiver)
1383 }
1384
1385 fn fulfill(self, guard: AllocGuard<Tx>) {
1393 let Self { sender, size: _ } = self;
1394 match sender.send(guard) {
1395 Ok(()) => (),
1396 Err(guard) => {
1397 drop(guard);
1400 }
1401 }
1402 }
1403}
1404
1405mod private {
1408 use super::{AllocKind, Rx, Tx};
1409 pub trait Sealed: 'static + Sized {}
1410 impl Sealed for Rx {}
1411 impl Sealed for Tx {}
1412
1413 pub struct Allocation<'a, K: AllocKind>(pub(super) &'a mut super::AllocGuard<K>);
1417}
1418
1419pub trait AllocKind: private::Sealed {
1422 const REFL: AllocKindRefl;
1424
1425 fn free(alloc: private::Allocation<'_, Self>);
1427}
1428
1429pub enum Tx {}
1431pub enum Rx {}
1433
1434pub enum AllocKindRefl {
1436 Tx,
1437 Rx,
1438}
1439
1440impl AllocKindRefl {
1441 pub(in crate::session) fn as_str(&self) -> &'static str {
1442 match self {
1443 AllocKindRefl::Tx => "Tx",
1444 AllocKindRefl::Rx => "Rx",
1445 }
1446 }
1447}
1448
1449impl AllocKind for Tx {
1450 const REFL: AllocKindRefl = AllocKindRefl::Tx;
1451
1452 fn free(alloc: private::Allocation<'_, Self>) {
1453 let private::Allocation(AllocGuard { pool, descs }) = alloc;
1454 pool.free_tx(std::mem::replace(descs, Chained::empty()));
1455 }
1456}
1457
1458impl AllocKind for Rx {
1459 const REFL: AllocKindRefl = AllocKindRefl::Rx;
1460
1461 fn free(alloc: private::Allocation<'_, Self>) {
1462 let private::Allocation(AllocGuard { pool, descs }) = alloc;
1463 pool.free_rx(std::mem::replace(descs, Chained::empty()));
1464 pool.rx_leases.rx_complete();
1465 }
1466}
1467
1468pub(in crate::session) struct RxLeaseHandlingState {
1470 can_watch_rx_leases: AtomicBool,
1471 rx_frame_counter: AtomicU64,
1481 rx_lease_waker: AtomicWaker,
1482}
1483
1484impl RxLeaseHandlingState {
1485 fn new_with_flags(flags: netdev::SessionFlags) -> Self {
1486 Self::new_with_enabled(flags.contains(netdev::SessionFlags::RECEIVE_RX_POWER_LEASES))
1487 }
1488
1489 fn new_with_enabled(enabled: bool) -> Self {
1490 Self {
1491 can_watch_rx_leases: AtomicBool::new(enabled),
1492 rx_frame_counter: AtomicU64::new(0),
1493 rx_lease_waker: AtomicWaker::new(),
1494 }
1495 }
1496
1497 fn rx_complete(&self) {
1500 let Self { can_watch_rx_leases: _, rx_frame_counter, rx_lease_waker } = self;
1501 let prev = rx_frame_counter.fetch_add(1, atomic::Ordering::SeqCst);
1502
1503 if prev == u64::MAX {
1506 rx_lease_waker.wake();
1507 }
1508 }
1509}
1510
1511pub(in crate::session) trait RxLeaseHandlingStateContainer {
1514 fn lease_handling_state(&self) -> &RxLeaseHandlingState;
1515}
1516
1517impl<T: Borrow<RxLeaseHandlingState>> RxLeaseHandlingStateContainer for T {
1518 fn lease_handling_state(&self) -> &RxLeaseHandlingState {
1519 self.borrow()
1520 }
1521}
1522
1523impl RxLeaseHandlingStateContainer for Arc<Pool> {
1524 fn lease_handling_state(&self) -> &RxLeaseHandlingState {
1525 &self.rx_leases
1526 }
1527}
1528
1529pub(in crate::session) struct RxLeaseWatcher<T> {
1531 state: T,
1532}
1533
1534impl<T: RxLeaseHandlingStateContainer> RxLeaseWatcher<T> {
1535 pub(in crate::session) fn new(state: T) -> Self {
1542 assert!(
1543 state.lease_handling_state().can_watch_rx_leases.swap(false, atomic::Ordering::SeqCst),
1544 "can't watch rx leases"
1545 );
1546 Self { state }
1547 }
1548
1549 pub(in crate::session) async fn wait_until(&mut self, hold_until_frame: u64) {
1558 let RxLeaseHandlingState { can_watch_rx_leases: _, rx_frame_counter, rx_lease_waker } =
1567 self.state.lease_handling_state();
1568
1569 let prev = rx_frame_counter.fetch_sub(hold_until_frame, atomic::Ordering::SeqCst);
1570 let _guard = scopeguard::guard((), |()| {
1573 let _: u64 = rx_frame_counter.fetch_add(hold_until_frame, atomic::Ordering::SeqCst);
1574 });
1575
1576 if prev >= hold_until_frame {
1578 return;
1579 }
1580 let threshold = prev.wrapping_sub(hold_until_frame);
1583 futures::future::poll_fn(|cx| {
1584 let v = rx_frame_counter.load(atomic::Ordering::SeqCst);
1585 if v < threshold {
1586 return Poll::Ready(());
1587 }
1588 rx_lease_waker.register(cx.waker());
1589 let v = rx_frame_counter.load(atomic::Ordering::SeqCst);
1590 if v < threshold {
1591 return Poll::Ready(());
1592 }
1593 Poll::Pending
1594 })
1595 .await;
1596 }
1597}
1598
1599#[cfg(test)]
1600mod tests {
1601
1602 use super::*;
1603
1604 use assert_matches::assert_matches;
1605 use fuchsia_async as fasync;
1606 use futures::future::FutureExt;
1607 use test_case::test_case;
1608
1609 use std::collections::HashSet;
1610 use std::num::{NonZeroU16, NonZeroU64, NonZeroUsize};
1611 use std::pin::pin;
1612 use std::task::Poll;
1613
1614 use crate::session::VmoConfig;
1615
1616 const DEFAULT_MIN_TX_BUFFER_HEAD: u16 = 4;
1617 const DEFAULT_MIN_TX_BUFFER_TAIL: u16 = 8;
1618 const DEFAULT_BUFFER_LENGTH: NonZeroUsize = NonZeroUsize::new(64).unwrap();
1620 const DEFAULT_TX_BUFFERS: NonZeroU16 = NonZeroU16::new(8).unwrap();
1621 const DEFAULT_RX_BUFFERS: NonZeroU16 = NonZeroU16::new(8).unwrap();
1622 const MAX_BUFFER_BYTES: usize = DEFAULT_BUFFER_LENGTH.get()
1623 * netdev::MAX_DESCRIPTOR_CHAIN as usize
1624 - DEFAULT_MIN_TX_BUFFER_HEAD as usize
1625 - DEFAULT_MIN_TX_BUFFER_TAIL as usize;
1626
1627 const SENTINEL_BYTE: u8 = 0xab;
1628 const WRITE_BYTE: u8 = 1;
1629 const PAD_BYTE: u8 = 0;
1630
1631 fn default_config() -> Config {
1632 Config {
1633 buffer_stride: NonZeroU64::new(DEFAULT_BUFFER_LENGTH.get() as u64).unwrap(),
1634 rx_vmos: vec![VmoConfig {
1635 vmo_id: DEFAULT_VMO_ID,
1636 num_buffers: DEFAULT_RX_BUFFERS.get(),
1637 }],
1638 tx_vmos: vec![VmoConfig {
1639 vmo_id: DEFAULT_VMO_ID,
1640 num_buffers: DEFAULT_TX_BUFFERS.get(),
1641 }],
1642 options: netdev::SessionFlags::empty(),
1643 buffer_layout: BufferLayout {
1644 length: DEFAULT_BUFFER_LENGTH.get(),
1645 min_tx_head: DEFAULT_MIN_TX_BUFFER_HEAD,
1646 min_tx_tail: DEFAULT_MIN_TX_BUFFER_TAIL,
1647 min_tx_data: 0,
1648 },
1649 buffer_usage_sample_interval: std::time::Duration::from_secs(1),
1650 }
1651 }
1652
1653 impl Pool {
1654 fn new_test_pool(config: Config) -> (Arc<Self>, zx::Vmo, Vec<zx::Vmo>) {
1655 let CreatedPool { pool, descriptors_vmo, data_vmos } =
1656 Pool::new(config).expect("failed to create pool");
1657 (pool, descriptors_vmo, data_vmos)
1658 }
1659
1660 fn new_test_default() -> Arc<Self> {
1661 let (pool, _descriptors, _data) = Pool::new_test_pool(default_config());
1662 pool
1663 }
1664
1665 fn tx_alloc_state_lock(&self) -> fuchsia_sync::MutexGuard<'_, TxAllocState> {
1666 self.tx_alloc_state.lock()
1667 }
1668
1669 async fn alloc_tx_checked(self: &Arc<Self>, n: u8) -> AllocGuard<Tx> {
1670 self.alloc_tx(ChainLength::try_from(n).expect("failed to convert to chain length"))
1671 .await
1672 }
1673
1674 fn alloc_tx_now_or_never(self: &Arc<Self>, n: u8) -> Option<AllocGuard<Tx>> {
1675 self.alloc_tx_checked(n).now_or_never()
1676 }
1677
1678 fn alloc_tx_all(self: &Arc<Self>, n: u8) -> Vec<AllocGuard<Tx>> {
1679 std::iter::from_fn(|| self.alloc_tx_now_or_never(n)).collect()
1680 }
1681
1682 fn alloc_tx_buffer_now_or_never(self: &Arc<Self>, num_bytes: usize) -> Option<Buffer<Tx>> {
1683 self.alloc_tx_buffer(num_bytes)
1684 .now_or_never()
1685 .transpose()
1686 .expect("invalid arguments for alloc_tx_buffer")
1687 }
1688
1689 fn set_min_tx_buffer_length(self: &mut Arc<Self>, length: usize) {
1690 Arc::get_mut(self).unwrap().buffer_layout.min_tx_data = length;
1691 }
1692
1693 fn fill_sentinel_bytes(&mut self) {
1694 let bytes = *self.vmo_offsets.last().unwrap();
1697 unsafe { std::ptr::write_bytes(self.base.as_ptr(), SENTINEL_BYTE, bytes) };
1698 }
1699 }
1700
1701 impl Buffer<Tx> {
1702 fn check_write_and_pad(&mut self, offset: usize, pad_size: usize) {
1706 {
1707 let mut io = self.io_mut();
1708 assert_eq!(io.write_at(offset, &[WRITE_BYTE][..]), 1);
1709 }
1710 assert_eq!(self.len(), pad_size);
1711 const INIT_BYTE: u8 = 42;
1714 let mut read_buf = vec![INIT_BYTE; pad_size];
1715 assert_eq!(self.io().read_at(0, &mut read_buf[..]), read_buf.len());
1716 for (idx, byte) in read_buf.iter().enumerate() {
1717 if idx < offset {
1718 assert_eq!(*byte, SENTINEL_BYTE);
1719 } else if idx == offset {
1720 assert_eq!(*byte, WRITE_BYTE);
1721 } else {
1722 assert_eq!(*byte, PAD_BYTE);
1723 }
1724 }
1725 }
1726 }
1727
1728 impl<K, I, T> PartialEq<T> for Chained<DescId<K>>
1729 where
1730 K: AllocKind,
1731 I: ExactSizeIterator<Item = u16>,
1732 T: Copy + IntoIterator<IntoIter = I>,
1733 {
1734 fn eq(&self, other: &T) -> bool {
1735 let iter = other.into_iter();
1736 if usize::from(self.len) != iter.len() {
1737 return false;
1738 }
1739 self.iter().zip(iter).all(|(l, r)| l.get() == r)
1740 }
1741 }
1742
1743 impl Debug for TxAllocReq {
1744 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1745 let TxAllocReq { sender: _, size } = self;
1746 f.debug_struct("TxAllocReq").field("size", &size).finish_non_exhaustive()
1747 }
1748 }
1749
1750 #[test]
1751 fn alloc_tx_distinct() {
1752 let pool = Pool::new_test_default();
1753 let allocated = pool.alloc_tx_all(1);
1754 assert_eq!(allocated.len(), usize::from(DEFAULT_TX_BUFFERS.get()));
1755 let distinct = allocated
1756 .iter()
1757 .map(|alloc| {
1758 assert_eq!(alloc.descs.len(), 1);
1759 alloc.descs[0].get()
1760 })
1761 .collect::<HashSet<u16>>();
1762 assert_eq!(allocated.len(), distinct.len());
1763 }
1764
1765 #[test]
1766 fn alloc_tx_free_len() {
1767 let pool = Pool::new_test_default();
1768 {
1769 let allocated = pool.alloc_tx_all(2);
1770 assert_eq!(
1771 allocated.iter().fold(0, |acc, a| { acc + a.descs.len() }),
1772 usize::from(DEFAULT_TX_BUFFERS.get())
1773 );
1774 assert_eq!(pool.tx_alloc_state_lock().free_lists[0].free, 0);
1775 }
1776 assert_eq!(pool.tx_alloc_state_lock().free_lists[0].free, DEFAULT_TX_BUFFERS.get());
1777 }
1778
1779 #[test]
1780 fn alloc_tx_chain() {
1781 let pool = Pool::new_test_default();
1782 let allocated = pool.alloc_tx_all(3);
1783 assert_eq!(allocated.len(), usize::from(DEFAULT_TX_BUFFERS.get()) / 3);
1784 assert_matches!(pool.alloc_tx_now_or_never(3), None);
1785 assert_matches!(pool.alloc_tx_now_or_never(2), Some(a) if a.descs.len() == 2);
1786 }
1787
1788 #[test]
1789 fn alloc_tx_many() {
1790 let pool = Pool::new_test_default();
1791 let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1792 - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
1793 - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
1794 let data_len = usize::try_from(data_len).unwrap();
1795 let mut buffers = pool
1796 .alloc_tx_buffers(data_len)
1797 .now_or_never()
1798 .expect("failed to alloc")
1799 .unwrap()
1800 .collect::<Result<Vec<_>>>()
1803 .expect("buffer error");
1804 assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()));
1805
1806 assert!(pool.alloc_tx_buffers(data_len).now_or_never().is_none());
1809
1810 assert_matches!(buffers.pop(), Some(_));
1812 let mut more_buffers =
1813 pool.alloc_tx_buffers(data_len).now_or_never().expect("failed to alloc").unwrap();
1814 let buffer = assert_matches!(more_buffers.next(), Some(Ok(b)) => b);
1815 assert_matches!(more_buffers.next(), None);
1816 drop(buffer);
1819 assert_matches!(more_buffers.next(), None);
1820 }
1821
1822 #[test]
1823 fn alloc_tx_after_free() {
1824 let pool = Pool::new_test_default();
1825 let mut allocated = pool.alloc_tx_all(1);
1826 assert_matches!(pool.alloc_tx_now_or_never(2), None);
1827 {
1828 let _drained = allocated.drain(..2);
1829 }
1830 assert_matches!(pool.alloc_tx_now_or_never(2), Some(a) if a.descs.len() == 2);
1831 }
1832
1833 #[test]
1834 fn blocking_alloc_tx() {
1835 let mut executor = fasync::TestExecutor::new();
1836 let pool = Pool::new_test_default();
1837 let mut allocated = pool.alloc_tx_all(1);
1838 let alloc_fut = pool.alloc_tx_checked(1);
1839 let mut alloc_fut = pin!(alloc_fut);
1840 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1842 assert!(!pool.tx_alloc_state_lock().requests.is_empty());
1844 let freed = allocated
1845 .pop()
1846 .expect("no fulfulled allocations")
1847 .iter()
1848 .map(|x| x.get())
1849 .collect::<Chained<_>>();
1850 let same_as_freed =
1851 |descs: &Chained<DescId<Tx>>| descs.iter().map(|x| x.get()).eq(freed.iter().copied());
1852 assert_matches!(
1854 &executor.run_until_stalled(&mut alloc_fut),
1855 Poll::Ready(AllocGuard{ descs, pool: _ }) if same_as_freed(descs)
1856 );
1857 assert!(pool.tx_alloc_state_lock().requests.is_empty());
1859 }
1860
1861 #[test]
1862 fn blocking_alloc_tx_cancel_before_free() {
1863 let mut executor = fasync::TestExecutor::new();
1864 let pool = Pool::new_test_default();
1865 let mut allocated = pool.alloc_tx_all(1);
1866 {
1867 let alloc_fut = pool.alloc_tx_checked(1);
1868 let mut alloc_fut = pin!(alloc_fut);
1869 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1870 assert_matches!(
1871 pool.tx_alloc_state_lock().requests.as_slices(),
1872 (&[ref req1, ref req2], &[]) if req1.size.get() == 1 && req2.size.get() == 1
1873 );
1874 }
1875 assert_matches!(
1876 allocated.pop(),
1877 Some(AllocGuard { ref descs, pool: ref p })
1878 if descs == &[DEFAULT_TX_BUFFERS.get() - 1] && Arc::ptr_eq(p, &pool)
1879 );
1880 let state = pool.tx_alloc_state_lock();
1881 assert_eq!(state.free_lists[0].free, 1);
1882 assert!(state.requests.is_empty());
1883 }
1884
1885 #[test]
1886 fn blocking_alloc_tx_cancel_after_free() {
1887 let mut executor = fasync::TestExecutor::new();
1888 let pool = Pool::new_test_default();
1889 let mut allocated = pool.alloc_tx_all(1);
1890 {
1891 let alloc_fut = pool.alloc_tx_checked(1);
1892 let mut alloc_fut = pin!(alloc_fut);
1893 assert_matches!(executor.run_until_stalled(&mut alloc_fut), Poll::Pending);
1894 assert_matches!(
1895 pool.tx_alloc_state_lock().requests.as_slices(),
1896 (&[ref req1, ref req2], &[]) if req1.size.get() == 1 && req2.size.get() == 1
1897 );
1898 assert_matches!(
1899 allocated.pop(),
1900 Some(AllocGuard { ref descs, pool: ref p })
1901 if descs == &[DEFAULT_TX_BUFFERS.get() - 1] && Arc::ptr_eq(p, &pool)
1902 );
1903 }
1904 let state = pool.tx_alloc_state_lock();
1905 assert_eq!(state.free_lists[0].free, 1);
1906 assert!(state.requests.is_empty());
1907 }
1908
1909 #[test]
1910 fn multiple_blocking_alloc_tx_fulfill_order() {
1911 const TASKS_TOTAL: usize = 3;
1912 let mut executor = fasync::TestExecutor::new();
1913 let pool = Pool::new_test_default();
1914 let mut allocated = pool.alloc_tx_all(1);
1915 let mut alloc_futs = (1..=TASKS_TOTAL)
1916 .rev()
1917 .map(|x| {
1918 let pool = pool.clone();
1919 (x, Box::pin(async move { pool.alloc_tx_checked(x.try_into().unwrap()).await }))
1920 })
1921 .collect::<Vec<_>>();
1922
1923 for (idx, (req_size, task)) in alloc_futs.iter_mut().enumerate() {
1924 assert_matches!(executor.run_until_stalled(task), Poll::Pending);
1925 assert_eq!(idx + *req_size, TASKS_TOTAL);
1927 }
1928 {
1929 let state = pool.tx_alloc_state_lock();
1930 assert_eq!(state.requests.len(), TASKS_TOTAL + 1);
1932 let mut requests = state.requests.iter();
1933 assert!(requests.next().unwrap().sender.is_canceled());
1936 assert!(requests.all(|req| !req.sender.is_canceled()))
1938 }
1939
1940 let mut to_free = Vec::new();
1941 let mut freed = 0;
1942 for free_size in (1..=TASKS_TOTAL).rev() {
1943 let (_req_size, mut task) = alloc_futs.remove(0);
1944 for _ in 1..free_size {
1945 freed += 1;
1946 assert_matches!(
1947 allocated.pop(),
1948 Some(AllocGuard { ref descs, pool: ref p })
1949 if descs == &[DEFAULT_TX_BUFFERS.get() - freed] && Arc::ptr_eq(p, &pool)
1950 );
1951 assert_matches!(executor.run_until_stalled(&mut task), Poll::Pending);
1952 }
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 match executor.run_until_stalled(&mut task) {
1960 Poll::Ready(alloc) => {
1961 assert_eq!(alloc.len(), free_size);
1962 to_free.push(alloc);
1964 }
1965 Poll::Pending => panic!("The request should be fulfilled"),
1966 }
1967 for (_req_size, task) in alloc_futs.iter_mut() {
1969 assert_matches!(executor.run_until_stalled(task), Poll::Pending);
1970 }
1971 }
1972 assert!(pool.tx_alloc_state_lock().requests.is_empty());
1973 }
1974
1975 #[test]
1976 fn singleton_tx_layout() {
1977 let pool = Pool::new_test_default();
1978 let buffers = std::iter::from_fn(|| {
1979 let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1980 - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
1981 - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
1982 pool.alloc_tx_buffer_now_or_never(usize::try_from(data_len).unwrap()).map(|buffer| {
1983 assert_eq!(buffer.alloc.descriptors().count(), 1);
1984 let offset = u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
1985 * u64::from(buffer.alloc[0].get());
1986 {
1987 let descriptor = buffer.alloc.descriptor();
1988 assert_matches!(descriptor.chain_length(), Ok(ChainLength::ZERO));
1989 assert_eq!(descriptor.head_length(), DEFAULT_MIN_TX_BUFFER_HEAD);
1990 assert_eq!(descriptor.tail_length(), DEFAULT_MIN_TX_BUFFER_TAIL);
1991 assert_eq!(descriptor.data_length(), data_len);
1992 assert_eq!(descriptor.offset(), offset);
1993 }
1994
1995 {
1996 let mut slices = buffer.parts();
1997 let slice = slices.next().expect("should have one slice");
1998 assert_matches!(slices.next(), None);
1999 assert_eq!(slice.len(), usize::try_from(data_len).unwrap());
2000 assert_eq!(
2001 slice.as_ptr(),
2002 pool.base.as_ptr().wrapping_add(
2003 usize::try_from(offset).unwrap()
2004 + usize::from(DEFAULT_MIN_TX_BUFFER_HEAD),
2005 )
2006 );
2007 }
2008 buffer
2009 })
2010 })
2011 .collect::<Vec<_>>();
2012 assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()));
2013 }
2014
2015 #[test]
2016 fn chained_tx_layout() {
2017 let pool = Pool::new_test_default();
2018 let alloc_len = 4 * DEFAULT_BUFFER_LENGTH.get()
2019 - usize::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2020 - usize::from(DEFAULT_MIN_TX_BUFFER_TAIL);
2021 let buffers = std::iter::from_fn(|| {
2022 pool.alloc_tx_buffer_now_or_never(alloc_len).map(|buffer| {
2023 assert_eq!(buffer.parts().count(), 4);
2024 for (idx, (descriptor, slice)) in
2025 buffer.alloc.descriptors().zip(buffer.parts()).enumerate()
2026 {
2027 let chain_length = ChainLength::try_from(buffer.alloc.len() - idx - 1).unwrap();
2028 let head_length = if idx == 0 { DEFAULT_MIN_TX_BUFFER_HEAD } else { 0 };
2029 let tail_length = if chain_length == ChainLength::ZERO {
2030 DEFAULT_MIN_TX_BUFFER_TAIL
2031 } else {
2032 0
2033 };
2034 let data_len = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2035 - u32::from(head_length)
2036 - u32::from(tail_length);
2037 let offset = u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2038 * u64::from(buffer.alloc[idx].get());
2039 assert_eq!(descriptor.chain_length().unwrap(), chain_length);
2040 assert_eq!(descriptor.head_length(), head_length);
2041 assert_eq!(descriptor.tail_length(), tail_length);
2042 assert_eq!(descriptor.offset(), offset);
2043 assert_eq!(descriptor.data_length(), data_len);
2044 if chain_length != ChainLength::ZERO {
2045 assert_eq!(descriptor.nxt(), Some(buffer.alloc[idx + 1].get()));
2046 }
2047
2048 assert_eq!(slice.len(), usize::try_from(data_len).unwrap());
2049 assert_eq!(
2050 slice.as_ptr(),
2051 pool.base.as_ptr().wrapping_add(
2052 usize::try_from(offset).unwrap() + usize::from(head_length),
2053 )
2054 );
2055 }
2056 buffer
2057 })
2058 })
2059 .collect::<Vec<_>>();
2060 assert_eq!(buffers.len(), usize::from(DEFAULT_TX_BUFFERS.get()) / 4);
2061 }
2062
2063 #[test]
2064 fn rx_distinct() {
2065 let pool = Pool::new_test_default();
2066 let mut guard = pool.rx_pending.lock();
2067 let descs = &mut guard.storage;
2068 assert_eq!(descs.len(), usize::from(DEFAULT_RX_BUFFERS.get()));
2069 let distinct = descs.iter().map(|desc| desc.get()).collect::<HashSet<u16>>();
2070 assert_eq!(descs.len(), distinct.len());
2071 }
2072
2073 #[test]
2074 fn alloc_rx_layout() {
2075 let pool = Pool::new_test_default();
2076 let mut guard = pool.rx_pending.lock();
2077 let descs = &mut guard.storage;
2078 assert_eq!(descs.len(), usize::from(DEFAULT_RX_BUFFERS.get()));
2079 for desc in descs.iter() {
2080 let descriptor = pool.descriptors.borrow(desc);
2081 let offset =
2082 u64::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap() * u64::from(desc.get());
2083 assert_matches!(descriptor.chain_length(), Ok(ChainLength::ZERO));
2084 assert_eq!(descriptor.head_length(), 0);
2085 assert_eq!(descriptor.tail_length(), 0);
2086 assert_eq!(descriptor.offset(), offset);
2087 assert_eq!(
2088 descriptor.data_length(),
2089 u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2090 );
2091 }
2092 }
2093
2094 #[test]
2095 fn buffer_read_at_write_at() {
2096 let pool = Pool::new_test_default();
2097 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2098 let mut buffer =
2099 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2100 assert_eq!(buffer.parts().count(), 2);
2103 assert_eq!(buffer.len(), alloc_bytes);
2104 let write_buf = (0..u8::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()).collect::<Vec<_>>();
2105 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), write_buf.len());
2106 let mut read_buf = [0xff; DEFAULT_BUFFER_LENGTH.get()];
2107 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), read_buf.len());
2108 for (idx, byte) in read_buf.iter().enumerate() {
2109 assert_eq!(*byte, write_buf[idx]);
2110 }
2111 }
2112
2113 #[test]
2114 fn buffer_write_at_short() {
2115 let pool = Pool::new_test_default();
2116 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2117 let mut buffer =
2118 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2119 assert_eq!(buffer.parts().count(), 2);
2120 assert_eq!(buffer.len(), alloc_bytes);
2121
2122 let write_buf = vec![WRITE_BYTE; alloc_bytes + 10];
2123
2124 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2126
2127 let mut read_buf = vec![0; alloc_bytes];
2129 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2130 for byte in read_buf.iter() {
2131 assert_eq!(*byte, WRITE_BYTE);
2132 }
2133
2134 assert_eq!(buffer.io_mut().write_at(alloc_bytes + 1, &write_buf[..]), 0);
2136
2137 let offset = alloc_bytes / 2;
2139 let expected_write = alloc_bytes - offset;
2140 let write_buf = vec![2; alloc_bytes]; assert_eq!(buffer.io_mut().write_at(offset, &write_buf[..]), expected_write);
2142
2143 let mut read_buf = vec![0; alloc_bytes];
2145 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2146 for (idx, byte) in read_buf.iter().enumerate() {
2147 if idx < offset {
2148 assert_eq!(*byte, WRITE_BYTE);
2149 } else {
2150 assert_eq!(*byte, 2);
2151 }
2152 }
2153 }
2154
2155 #[test]
2156 fn buffer_read_at_short() {
2157 let pool = Pool::new_test_default();
2158 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2159 let mut buffer =
2160 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2161 assert_eq!(buffer.parts().count(), 2);
2162 assert_eq!(buffer.len(), alloc_bytes);
2163
2164 let write_buf = vec![WRITE_BYTE; alloc_bytes];
2165 assert_eq!(buffer.io_mut().write_at(0, &write_buf[..]), alloc_bytes);
2166
2167 let mut read_buf = vec![0xff; alloc_bytes + 10];
2169 assert_eq!(buffer.io().read_at(0, &mut read_buf[..]), alloc_bytes);
2170 for (idx, byte) in read_buf.iter().enumerate() {
2171 if idx < alloc_bytes {
2172 assert_eq!(*byte, WRITE_BYTE);
2173 } else {
2174 assert_eq!(*byte, 0xff);
2175 }
2176 }
2177
2178 assert_eq!(buffer.io().read_at(alloc_bytes + 1, &mut read_buf[..]), 0);
2180
2181 let offset = alloc_bytes / 2;
2183 let expected_read = alloc_bytes - offset;
2184 let mut read_buf = vec![0xff; alloc_bytes];
2185 assert_eq!(buffer.io().read_at(offset, &mut read_buf[..]), expected_read);
2186 for (idx, byte) in read_buf.iter().enumerate() {
2187 if idx < expected_read {
2188 assert_eq!(*byte, WRITE_BYTE);
2189 } else {
2190 assert_eq!(*byte, 0xff);
2191 }
2192 }
2193 }
2194
2195 #[test]
2196 fn buffer_read_write_seek() {
2197 let pool = Pool::new_test_default();
2198 let alloc_bytes = DEFAULT_BUFFER_LENGTH.get();
2199 let mut buffer =
2200 pool.alloc_tx_buffer_now_or_never(alloc_bytes).expect("failed to allocate");
2201 assert_eq!(buffer.parts().count(), 2);
2204 assert_eq!(buffer.len(), alloc_bytes);
2205 let write_buf = (0..u8::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()).collect::<Vec<_>>();
2206
2207 let mut io = buffer.io_mut();
2208
2209 assert_eq!(io.write(&write_buf[..]).expect("failed to write into buffer"), write_buf.len());
2210 const SEEK_FROM_END: usize = 64;
2211 const READ_LEN: usize = 12;
2212 assert_eq!(
2213 io.seek(SeekFrom::End(-i64::try_from(SEEK_FROM_END).unwrap())).unwrap(),
2214 u64::try_from(io.len - SEEK_FROM_END).unwrap()
2215 );
2216 let mut read_buf = [0xff; READ_LEN];
2217 assert_eq!(io.read(&mut read_buf[..]).expect("failed to read from buffer"), read_buf.len());
2218 assert_eq!(&write_buf[..READ_LEN], &read_buf[..]);
2219 }
2220
2221 #[test_case(32; "single buffer part")]
2222 #[test_case(MAX_BUFFER_BYTES; "multiple buffer parts")]
2223 fn buffer_pad(pad_size: usize) {
2224 let mut pool = Pool::new_test_default();
2225 pool.set_min_tx_buffer_length(pad_size);
2226 for offset in 0..pad_size {
2227 Arc::get_mut(&mut pool)
2228 .expect("there are multiple owners of the underlying VMO")
2229 .fill_sentinel_bytes();
2230 let mut buffer =
2231 pool.alloc_tx_buffer_now_or_never(offset + 1).expect("failed to allocate buffer");
2232 buffer.check_write_and_pad(offset, pad_size);
2233 }
2234 }
2235
2236 #[test]
2237 fn buffer_pad_grow() {
2238 const BUFFER_PARTS: u8 = 3;
2239 let mut pool = Pool::new_test_default();
2240 let pad_size = u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap()
2241 * u32::from(BUFFER_PARTS)
2242 - u32::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2243 - u32::from(DEFAULT_MIN_TX_BUFFER_TAIL);
2244 pool.set_min_tx_buffer_length(pad_size.try_into().unwrap());
2245 for offset in 0..pad_size - u32::try_from(DEFAULT_BUFFER_LENGTH.get()).unwrap() {
2246 Arc::get_mut(&mut pool)
2247 .expect("there are multiple owners of the underlying VMO")
2248 .fill_sentinel_bytes();
2249 let mut alloc =
2250 pool.alloc_tx_now_or_never(BUFFER_PARTS).expect("failed to alloc descriptors");
2251 alloc
2252 .init(usize::try_from(offset).unwrap() + 1)
2253 .expect("head/body/tail sizes are representable with u16/u32/u16");
2254 let mut buffer = Buffer::try_from(alloc).unwrap();
2255 buffer.check_write_and_pad(offset.try_into().unwrap(), pad_size.try_into().unwrap());
2256 }
2257 }
2258
2259 #[test_case( 0; "writes at the beginning")]
2260 #[test_case( 15; "writes in the first part")]
2261 #[test_case( 75; "writes in the second part")]
2262 #[test_case(135; "writes in the third part")]
2263 #[test_case(195; "writes in the last part")]
2264 fn buffer_used(write_offset: usize) {
2265 let pool = Pool::new_test_default();
2266 let mut buffer =
2267 pool.alloc_tx_buffer_now_or_never(MAX_BUFFER_BYTES).expect("failed to allocate buffer");
2268 let expected_caps = (0..netdev::MAX_DESCRIPTOR_CHAIN).map(|i| {
2269 if i == 0 {
2270 DEFAULT_BUFFER_LENGTH.get() - usize::from(DEFAULT_MIN_TX_BUFFER_HEAD)
2271 } else if i < netdev::MAX_DESCRIPTOR_CHAIN - 1 {
2272 DEFAULT_BUFFER_LENGTH.get()
2273 } else {
2274 DEFAULT_BUFFER_LENGTH.get() - usize::from(DEFAULT_MIN_TX_BUFFER_TAIL)
2275 }
2276 });
2277 assert_eq!(buffer.alloc.len(), usize::from(netdev::MAX_DESCRIPTOR_CHAIN));
2278 assert_eq!(buffer.io_mut().write_at(write_offset, &[WRITE_BYTE][..]), 1);
2279 assert_eq!(
2282 buffer.parts().zip(expected_caps).fold(
2283 Some(write_offset),
2284 |offset, (slice, expected_cap)| {
2285 assert_eq!(slice.len(), expected_cap);
2286 match offset {
2287 Some(offset) => {
2288 if offset >= expected_cap {
2289 Some(offset - slice.len())
2290 } else {
2291 assert_eq!(slice[offset], WRITE_BYTE);
2292 None
2293 }
2294 }
2295 None => None,
2296 }
2297 }
2298 ),
2299 None
2300 );
2301 }
2302
2303 #[test]
2304 fn allocate_under_device_minimum() {
2305 const MIN_TX_DATA: usize = 32;
2306 const ALLOC_SIZE: usize = 16;
2307 const WRITE_BYTE: u8 = 0xff;
2308 const WRITE_SENTINAL_BYTE: u8 = 0xee;
2309 const READ_SENTINAL_BYTE: u8 = 0xdd;
2310 let mut config = default_config();
2311 config.buffer_layout.min_tx_data = MIN_TX_DATA;
2312 let (pool, _descriptors, _vmo) = Pool::new_test_pool(config);
2313 for mut buffer in Vec::from_iter(std::iter::from_fn({
2314 let pool = pool.clone();
2315 move || pool.alloc_tx_buffer_now_or_never(MIN_TX_DATA)
2316 })) {
2317 assert_eq!(
2318 buffer.io_mut().write_at(0, &[WRITE_SENTINAL_BYTE; MIN_TX_DATA]),
2319 MIN_TX_DATA
2320 );
2321 }
2322 let mut allocated =
2323 pool.alloc_tx_buffer_now_or_never(16).expect("failed to allocate buffer");
2324 assert_eq!(allocated.len(), MIN_TX_DATA);
2325 const WRITE_BUF_SIZE: usize = MIN_TX_DATA + 1;
2326 assert_eq!(allocated.io_mut().write_at(0, &[WRITE_BYTE; WRITE_BUF_SIZE]), MIN_TX_DATA);
2327 assert_eq!(allocated.io_mut().write_at(0, &[WRITE_BYTE; ALLOC_SIZE]), ALLOC_SIZE);
2328 assert_eq!(allocated.len(), MIN_TX_DATA);
2329 const READ_BUF_SIZE: usize = MIN_TX_DATA + 1;
2330 let mut read_buf = [READ_SENTINAL_BYTE; READ_BUF_SIZE];
2331 assert_eq!(allocated.io().read_at(0, &mut read_buf[..]), MIN_TX_DATA);
2332 assert_eq!(allocated.io().read_at(0, &mut read_buf[..MIN_TX_DATA]), MIN_TX_DATA);
2333 assert_eq!(&read_buf[..ALLOC_SIZE], &[WRITE_BYTE; ALLOC_SIZE][..]);
2334 assert_eq!(&read_buf[ALLOC_SIZE..MIN_TX_DATA], &[WRITE_BYTE; ALLOC_SIZE][..]);
2335 assert_eq!(&read_buf[MIN_TX_DATA..], &[READ_SENTINAL_BYTE; 1][..]);
2336 }
2337
2338 #[test]
2339 fn invalid_tx_length() {
2340 let mut config = default_config();
2341 config.buffer_layout.length = usize::from(u16::MAX) + 2;
2342 config.buffer_layout.min_tx_head = 0;
2343 let (pool, _descriptors, _vmo) = Pool::new_test_pool(config);
2344 assert_matches!(pool.alloc_tx_buffer(1).now_or_never(), Some(Err(Error::TxLength)));
2345 }
2346
2347 #[test]
2348 fn vmo_indices_tracking() {
2349 let mut config = default_config();
2350 config.rx_vmos = vec![VmoConfig { vmo_id: 0, num_buffers: DEFAULT_RX_BUFFERS.get() }];
2351 config.tx_vmos =
2352 vec![VmoConfig { vmo_id: 1, num_buffers: 2 }, VmoConfig { vmo_id: 2, num_buffers: 4 }];
2353
2354 let (pool, _descriptors, _vmos) = Pool::new_test_pool(config);
2355
2356 {
2359 let state = pool.tx_alloc_state_lock();
2360 assert_eq!(state.first_available_index, 0);
2361 }
2362
2363 let alloc1 = pool.alloc_tx_now_or_never(1).expect("alloc 1");
2365 {
2366 let state = pool.tx_alloc_state_lock();
2367 assert_eq!(state.first_available_index, 0);
2369 }
2370
2371 let alloc2 = pool.alloc_tx_now_or_never(1).expect("alloc 2");
2373 {
2374 let state = pool.tx_alloc_state_lock();
2375 assert_eq!(state.first_available_index, 1);
2377 }
2378
2379 let alloc3 = pool.alloc_tx_now_or_never(1).expect("alloc 3");
2381 {
2382 let state = pool.tx_alloc_state_lock();
2383 assert_eq!(state.first_available_index, 1);
2385 }
2386
2387 let _alloc4 = pool.alloc_tx_now_or_never(1).expect("alloc 4");
2389 let _alloc5 = pool.alloc_tx_now_or_never(1).expect("alloc 5");
2390 let _alloc6 = pool.alloc_tx_now_or_never(1).expect("alloc 6");
2391 {
2392 let state = pool.tx_alloc_state_lock();
2393 assert_eq!(state.first_available_index, state.free_lists.len());
2394 }
2395
2396 drop(alloc1);
2398 {
2399 let state = pool.tx_alloc_state_lock();
2400 assert_eq!(state.first_available_index, 0);
2402 }
2403
2404 drop(alloc3);
2406 {
2407 let state = pool.tx_alloc_state_lock();
2408 assert_eq!(state.first_available_index, 0);
2410 }
2411
2412 drop(alloc2);
2414 {
2415 let state = pool.tx_alloc_state_lock();
2416 assert_eq!(state.first_available_index, 0);
2418 }
2419 }
2420
2421 #[test]
2422 fn rx_leases() {
2423 let mut executor = fuchsia_async::TestExecutor::new();
2424 let state = RxLeaseHandlingState::new_with_enabled(true);
2425 let mut watcher = RxLeaseWatcher { state: &state };
2426
2427 {
2428 let mut fut = pin!(watcher.wait_until(0));
2429 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
2430 }
2431 {
2432 state.rx_complete();
2433 let mut fut = pin!(watcher.wait_until(1));
2434 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
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 let mut fut = pin!(watcher.wait_until(3));
2442 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2443 state.rx_complete();
2444 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2445 state.rx_complete();
2446 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Ready(()));
2447 }
2448 let counter_before = state.rx_frame_counter.load(atomic::Ordering::SeqCst);
2451 {
2452 let mut fut = pin!(watcher.wait_until(10000));
2453 assert_eq!(executor.run_until_stalled(&mut fut), Poll::Pending);
2454 }
2455 let counter_after = state.rx_frame_counter.load(atomic::Ordering::SeqCst);
2456 assert_eq!(counter_before, counter_after);
2457 }
2458
2459 #[test]
2460 #[should_panic(expected = "slice end")]
2461 fn get_slice_out_of_bounds_panic() {
2462 let mut config = default_config();
2463 config.buffer_layout.length = 64;
2464 config.buffer_stride = NonZeroU64::new(64).unwrap();
2465 config.tx_vmos = vec![VmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: 1 }];
2466
2467 let (mut pool, _descriptors_vmo, _data_vmos) = Pool::new_test_pool(config);
2468 Arc::get_mut(&mut pool)
2469 .expect("there are multiple owners of the underlying VMO")
2470 .fill_sentinel_bytes();
2471
2472 let mut buffer = pool.alloc_tx_buffer_now_or_never(10).expect("failed to alloc buffer");
2473 {
2474 let mut desc = buffer.alloc.descriptor_mut();
2475 desc.set_data_length(4093);
2476 }
2477 let _slice = buffer.as_slice_mut();
2478 }
2479}