1mod buffer;
8mod tx;
9
10use std::fmt::Debug;
11use std::mem::MaybeUninit;
12use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize, TryFromIntError};
13use std::ops::Range;
14use std::pin::Pin;
15use std::sync::Arc;
16use std::sync::atomic::{self, AtomicUsize};
17use std::task::Waker;
18
19use explicit::{PollExt as _, ResultExt as _};
20use fidl_fuchsia_hardware_network as netdev;
21use fidl_fuchsia_hardware_network::DelegatedRxLease;
22use fidl_table_validation::ValidFidlTable;
23use fuchsia_async as fasync;
24use fuchsia_sync::Mutex;
25use futures::future::{Future, poll_fn};
26use futures::task::{Context, Poll};
27use futures::{Stream, StreamExt as _, ready};
28
29use crate::error::{Error, Result};
30use buffer::pool::{CreatedPool, Pool, RxLeaseWatcher};
31use buffer::{
32 AllocKind, DescId, NETWORK_DEVICE_DESCRIPTOR_LENGTH, NETWORK_DEVICE_DESCRIPTOR_VERSION,
33};
34pub use buffer::{
35 Buffer, ChecksumRxOffloading, Rx, RxMetadata, SinglePartTxBuffer, Tx, TxMetadataMut,
36};
37use tx::{BufferUsageEstimator, TxState, TxVmoConfig};
38
39const DEFAULT_VMO_ID: u8 = 0;
43
44#[derive(Clone)]
46pub struct Session {
47 inner: Arc<Inner>,
48}
49
50impl Debug for Session {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 let Self { inner } = self;
53 let Inner { name, .. } = &**inner;
54 f.debug_struct("Session").field("name", &name).finish_non_exhaustive()
55 }
56}
57
58impl Session {
59 pub async fn new(
61 device: &netdev::DeviceProxy,
62 name: &str,
63 config: Config,
64 ) -> Result<(Self, Task)> {
65 let sample_interval = config.buffer_usage_sample_interval;
66 let inner = Inner::new(device, name, config).await?;
67 let buffer_usage_sampler = inner
68 .pool
69 .has_decommittable_tx_vmo()
70 .then(|| (fasync::Interval::new(sample_interval.into()), BufferUsageEstimator::new()));
71
72 Ok((Session { inner: Arc::clone(&inner) }, Task { inner, buffer_usage_sampler }))
73 }
74
75 pub fn send(&self, buffer: Buffer<Tx>) {
77 self.inner.send(buffer)
78 }
79
80 pub fn new_rx_ready_storage(&self) -> RxReadyStorage {
86 RxReadyStorage::new(self.inner.num_rx_buffers)
87 }
88
89 pub async fn recv<'a>(
92 &'a self,
93 ready_storage: &'a mut RxReadyStorage,
94 ) -> Result<impl Iterator<Item = Result<Buffer<Rx>>> + 'a> {
95 self.inner.recv(ready_storage).await
96 }
97
98 pub async fn alloc_tx_buffer(&self, num_bytes: usize) -> Result<Buffer<Tx>> {
102 self.inner.pool.alloc_tx_buffer(num_bytes).await
103 }
104
105 pub fn try_alloc_single_part_tx_buffer(
110 &self,
111 num_bytes: usize,
112 ) -> Result<Option<SinglePartTxBuffer>> {
113 self.inner.pool.try_alloc_single_part_tx_buffer(num_bytes)
114 }
115
116 pub async fn alloc_tx_buffers(
129 &self,
130 num_bytes: usize,
131 ) -> Result<impl Iterator<Item = Result<Buffer<Tx>>> + '_> {
132 self.inner.pool.alloc_tx_buffers(num_bytes).await
133 }
134
135 pub async fn attach(&self, port: Port, rx_frames: &[netdev::FrameType]) -> Result<()> {
137 let fut = self.inner.proxy.attach(&port.into(), rx_frames);
144 let () = fut.await?.map_err(|raw| Error::Attach(port, zx::Status::from_raw(raw)))?;
145 Ok(())
146 }
147
148 pub async fn detach(&self, port: Port) -> Result<()> {
150 let () = self
151 .inner
152 .proxy
153 .detach(&port.into())
154 .await?
155 .map_err(|raw| Error::Detach(port, zx::Status::from_raw(raw)))?;
156 Ok(())
157 }
158
159 pub async fn wait_tx_idle(&self) {
172 self.inner.tx_idle_listeners.wait().await;
173 }
174
175 pub fn watch_rx_leases(&self) -> impl Stream<Item = Result<RxLease>> + Send + Sync + use<> {
190 let inner = Arc::clone(&self.inner);
191 let watcher = RxLeaseWatcher::new(Arc::clone(&inner.pool));
192 futures::stream::try_unfold((inner, watcher), |(inner, mut watcher)| async move {
193 let DelegatedRxLease {
194 hold_until_frame,
195 handle,
196 __source_breaking: fidl::marker::SourceBreaking,
197 } = match inner.proxy.watch_delegated_rx_lease().await {
198 Ok(lease) => lease,
199 Err(e) => {
200 if e.is_closed() {
201 return Ok(None);
202 } else {
203 return Err(Error::Fidl(e));
204 }
205 }
206 };
207 let hold_until_frame = hold_until_frame.ok_or(Error::InvalidLease)?;
208 let handle = RxLease { handle: handle.ok_or(Error::InvalidLease)? };
209
210 watcher.wait_until(hold_until_frame).await;
211 Ok(Some((handle, (inner, watcher))))
212 })
213 }
214
215 pub async fn close(&self) -> Result<()> {
217 self.inner.proxy.close()?;
218 let mut event_stream = self.inner.proxy.take_event_stream();
220 while let Some(event) = event_stream.next().await {
221 match event {
222 Err(fidl::Error::ClientChannelClosed { .. }) => break,
223 Ok(_) => {} Err(e) => return Err(Error::Fidl(e)),
225 }
226 }
227 Ok(())
228 }
229}
230
231struct Inner {
232 pool: Arc<Pool>,
233 proxy: netdev::SessionProxy,
234 name: String,
235 rx: fasync::Fifo<DescId<Rx>>,
236 tx: fasync::Fifo<DescId<Tx>>,
237 num_rx_buffers: usize,
238 tx_ready: Mutex<ReadyStorage<DescId<Tx>>>,
239 tx_idle_listeners: TxIdleListeners,
240 tx_state: Mutex<TxState>,
241}
242
243impl Inner {
244 async fn new(device: &netdev::DeviceProxy, name: &str, config: Config) -> Result<Arc<Self>> {
246 let CreatedPool { pool, descriptors_vmo, data_vmos } = Pool::new(config.clone())?;
247 let tx_vmo_cumulative_buffers = {
248 let mut cumulative = 0u16;
249 config
250 .tx_vmos
251 .iter()
252 .map(|vmo_config| {
253 cumulative += vmo_config.num_buffers;
254 cumulative
255 })
256 .collect::<Vec<_>>()
257 };
258 let tx_state = Mutex::new(TxState::new(tx_vmo_cumulative_buffers));
259
260 let session_info = {
261 let descriptor_length =
264 u8::try_from(NETWORK_DEVICE_DESCRIPTOR_LENGTH / std::mem::size_of::<u64>())
265 .expect("descriptor length in 64-bit words not representable by u8");
266 let data = data_vmos
267 .into_iter()
268 .enumerate()
269 .map(|(idx, vmo)| {
270 let vmo_id = netdev::VmoId::try_from(idx).expect("invalid vmo id");
271 let num_rx_buffers =
272 if vmo_id == DEFAULT_VMO_ID { config.num_rx_buffers.get() } else { 0 };
273 fidl_fuchsia_hardware_network::DataVmo {
274 id: Some(vmo_id),
275 vmo: Some(vmo),
276 num_rx_buffers: Some(num_rx_buffers),
277 __source_breaking: fidl::marker::SourceBreaking,
278 }
279 })
280 .collect::<Vec<_>>();
281 netdev::SessionInfo {
282 descriptors: Some(descriptors_vmo),
283 data: Some(data),
284 descriptor_version: Some(NETWORK_DEVICE_DESCRIPTOR_VERSION),
285 descriptor_length: Some(descriptor_length),
286 descriptor_count: Some(config.num_tx_buffers().get() + config.num_rx_buffers.get()),
287 options: Some(config.options),
288 ..Default::default()
289 }
290 };
291
292 let (client, netdev::Fifos { rx, tx }) = device
293 .open_session(name, session_info)
294 .await?
295 .map_err(|raw| Error::Open(name.to_owned(), zx::Status::from_raw(raw)))?;
296 let proxy = client.into_proxy();
297
298 let rx = fasync::Fifo::from_fifo(rx);
299 let tx = fasync::Fifo::from_fifo(tx);
300
301 let vmos_to_register = if pool.has_decommittable_tx_vmo() {
302 &pool.decommittable_tx_vmo_ids[0..=0]
304 } else {
305 &[DEFAULT_VMO_ID]
306 };
307 let (s, status) = proxy.register_for_tx(vmos_to_register).await.map_err(Error::Fidl)?;
308 zx::Status::ok(status).map_err(Error::RegisterForTx)?;
309 assert_eq!(s, 1);
310
311 let num_rx_buffers = config.num_rx_buffers.get().into();
312
313 Ok(Arc::new(Self {
314 pool,
315 proxy,
316 name: name.to_owned(),
317 rx,
318 tx,
319 num_rx_buffers,
320 tx_ready: Mutex::new(ReadyStorage::new(config.num_tx_buffers().get().into())),
321 tx_idle_listeners: TxIdleListeners::new(),
322 tx_state,
323 }))
324 }
325
326 fn poll_submit_rx(&self, cx: &mut Context<'_>) -> Poll<Result<usize>> {
330 self.pool.rx_pending.lock().poll_submit(&self.rx, cx)
331 }
332
333 fn poll_submit_tx(&self, cx: &mut Context<'_>) -> Poll<Result<usize>> {
337 self.tx_state.lock().poll_submit_tx(&self.proxy, &self.pool, &self.tx, cx)
338 }
339
340 fn poll_complete_tx(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
342 let (count, result) = {
343 let mut tx_ready = self.tx_ready.lock();
344 ready!(tx_ready.poll_fifo(cx, &self.tx))
345 .map_err(|status| Error::Fifo("read", "tx", status))?;
346 tx_ready
350 .drain()
351 .try_fold(0, |count, desc| match self.pool.tx_completed(desc) {
352 Ok(()) => Ok(count + 1),
353 Err(e) => Err((count, e)),
354 })
355 .map_or_else(|(count, e)| (count, Err(e)), |count| (count, Ok(())))
356 };
357 self.tx_idle_listeners.tx_complete(count);
358 result?;
359 Poll::Ready(Ok(()))
360 }
361
362 fn send(&self, buffer: Buffer<Tx>) {
369 self.tx_idle_listeners.tx_started();
370 let mut state = self.tx_state.lock();
371 state.send(&self.proxy, &self.pool, buffer);
372 }
373
374 async fn recv<'a>(
378 &'a self,
379 ready_storage: &'a mut RxReadyStorage,
380 ) -> Result<impl Iterator<Item = Result<Buffer<Rx>>> + 'a> {
381 poll_fn(|cx| ready_storage.poll_fifo(cx, &self.rx))
382 .await
383 .map_err(|status| Error::Fifo("read", "rx", status))?;
384 Ok(ready_storage.drain().map(move |head| self.pool.rx_completed(head)))
385 }
386}
387
388#[must_use = "futures do nothing unless you `.await` or poll them"]
392pub struct Task {
393 inner: Arc<Inner>,
394 buffer_usage_sampler: Option<(fasync::Interval, BufferUsageEstimator)>,
395}
396
397impl Future for Task {
398 type Output = Result<()>;
399 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
400 let this = self.as_mut().get_mut();
401 let inner = &*this.inner;
402 loop {
403 let mut all_pending = true;
404
405 while inner.poll_complete_tx(cx)?.is_ready_checked::<()>() {
408 all_pending = false;
409 }
410 if inner.poll_submit_rx(cx)?.is_ready_checked::<usize>() {
411 all_pending = false;
412 }
413 if inner.poll_submit_tx(cx)?.is_ready_checked::<usize>() {
414 all_pending = false;
415 }
416
417 if !all_pending {
418 continue;
419 }
420
421 if let Some((interval, estimator)) = &mut this.buffer_usage_sampler {
422 while interval.poll_next_unpin(cx).is_ready_checked::<Option<()>>() {
423 let buffer_usage_estimate = {
424 let mut state = inner.pool.tx_alloc_state.lock();
425 estimator.update(state.sample_peak_buffer_usage())
426 };
427 if inner.tx_state.lock().attempt_unregister(
428 buffer_usage_estimate,
429 &inner.proxy,
430 &inner.pool,
431 ) {
432 all_pending = false;
433 }
434 }
435 }
436
437 if all_pending {
438 return Poll::Pending;
439 }
440 }
441 }
442}
443
444#[derive(Debug, Clone)]
446pub struct Config {
447 buffer_stride: NonZeroU64,
449 num_rx_buffers: NonZeroU16,
451 tx_vmos: Vec<TxVmoConfig>,
453 options: netdev::SessionFlags,
455 buffer_layout: BufferLayout,
457 buffer_usage_sample_interval: std::time::Duration,
458}
459
460impl Config {
461 pub fn num_tx_buffers(&self) -> NonZeroU16 {
463 let sum: u16 = self.tx_vmos.iter().map(|v| v.num_buffers).sum();
464 NonZeroU16::new(sum).expect("num_tx_buffers is zero")
465 }
466}
467
468#[derive(Debug, Clone, Copy)]
470struct BufferLayout {
471 min_tx_data: usize,
473 min_tx_head: u16,
475 min_tx_tail: u16,
477 length: usize,
479}
480
481#[derive(Debug, Clone, ValidFidlTable)]
483#[fidl_table_src(netdev::DeviceBaseInfo)]
484#[fidl_table_strict]
485pub struct DeviceBaseInfo {
486 pub rx_depth: u16,
488 pub tx_depth: u16,
490 pub buffer_alignment: u32,
492 #[fidl_field_type(optional)]
494 pub max_buffer_length: Option<NonZeroU32>,
495 pub min_rx_buffer_length: u32,
497 pub min_tx_buffer_length: u32,
499 pub min_tx_buffer_head: u16,
501 pub min_tx_buffer_tail: u16,
503 pub max_buffer_parts: u8,
505 #[fidl_field_type(optional)]
508 pub min_rx_buffers: Option<NonZeroU16>,
509}
510
511#[derive(Debug, Clone, ValidFidlTable)]
513#[fidl_table_src(netdev::DeviceInfo)]
514#[fidl_table_strict]
515pub struct DeviceInfo {
516 pub min_descriptor_length: u8,
518 pub descriptor_version: u8,
520 pub base_info: DeviceBaseInfo,
522}
523
524#[derive(Debug, Copy, Clone)]
527pub struct DerivableConfig {
528 pub default_buffer_length: usize,
530 pub watch_rx_leases: bool,
532 pub multi_vmo: bool,
534 pub buffer_usage_sample_interval: std::time::Duration,
536}
537
538impl DerivableConfig {
539 pub const DEFAULT_BUFFER_LENGTH: usize = 2048;
546 pub const DEFAULT: Self = Self {
548 default_buffer_length: Self::DEFAULT_BUFFER_LENGTH,
549 watch_rx_leases: false,
550 multi_vmo: false,
551 buffer_usage_sample_interval: std::time::Duration::from_secs(1),
552 };
553}
554
555impl Default for DerivableConfig {
556 fn default() -> Self {
557 Self::DEFAULT
558 }
559}
560
561impl DeviceInfo {
562 pub fn make_config(&self, config: DerivableConfig) -> Result<Config> {
567 let DeviceInfo {
568 min_descriptor_length,
569 descriptor_version,
570 base_info:
571 DeviceBaseInfo {
572 rx_depth,
573 tx_depth,
574 buffer_alignment,
575 max_buffer_length,
576 min_rx_buffer_length,
577 min_tx_buffer_length,
578 min_tx_buffer_head,
579 min_tx_buffer_tail,
580 max_buffer_parts: _,
581 min_rx_buffers: _,
582 },
583 } = self;
584 if NETWORK_DEVICE_DESCRIPTOR_VERSION != *descriptor_version {
585 return Err(Error::Config(format!(
586 "descriptor version mismatch: {} != {}",
587 NETWORK_DEVICE_DESCRIPTOR_VERSION, descriptor_version
588 )));
589 }
590 if NETWORK_DEVICE_DESCRIPTOR_LENGTH < usize::from(*min_descriptor_length) {
591 return Err(Error::Config(format!(
592 "descriptor length too small: {} < {}",
593 NETWORK_DEVICE_DESCRIPTOR_LENGTH, min_descriptor_length
594 )));
595 }
596
597 let DerivableConfig {
598 default_buffer_length,
599 watch_rx_leases,
600 multi_vmo,
601 buffer_usage_sample_interval,
602 } = config;
603
604 let num_rx_buffers =
605 NonZeroU16::new(*rx_depth).ok_or_else(|| Error::Config("no RX buffers".to_owned()))?;
606 if *tx_depth == 0 {
607 return Err(Error::Config("no TX buffers".to_owned()));
608 }
609
610 let max_buffer_length = max_buffer_length
611 .and_then(|max| {
612 usize::try_from(max.get()).ok_checked::<TryFromIntError>()
616 })
617 .unwrap_or(usize::MAX);
618 let min_buffer_length = usize::try_from(*min_rx_buffer_length)
619 .ok_checked::<TryFromIntError>()
620 .unwrap_or(usize::MAX);
621
622 let buffer_length =
623 usize::min(max_buffer_length, usize::max(min_buffer_length, default_buffer_length));
624
625 let buffer_alignment = usize::try_from(*buffer_alignment).map_err(
626 |std::num::TryFromIntError { .. }| {
627 Error::Config(format!(
628 "buffer_alignment not representable within usize: {}",
629 buffer_alignment,
630 ))
631 },
632 )?;
633
634 let buffer_stride = buffer_length
635 .checked_add(buffer_alignment - 1)
636 .map(|x| x / buffer_alignment * buffer_alignment)
637 .ok_or_else(|| {
638 Error::Config(format!(
639 "not possible to align {} to {} under usize::MAX",
640 buffer_length, buffer_alignment,
641 ))
642 })?;
643
644 if buffer_stride < buffer_length {
645 return Err(Error::Config(format!(
646 "buffer stride too small {} < {}",
647 buffer_stride, buffer_length
648 )));
649 }
650
651 if buffer_length < usize::from(*min_tx_buffer_head) + usize::from(*min_tx_buffer_tail) {
652 return Err(Error::Config(format!(
653 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/{}",
654 buffer_length, min_tx_buffer_head, min_tx_buffer_tail,
655 )));
656 }
657
658 let num_buffers =
659 rx_depth.checked_add(*tx_depth).filter(|num| *num != u16::MAX).ok_or_else(|| {
660 Error::Config(format!(
661 "too many buffers requested: {} + {} > u16::MAX",
662 rx_depth, tx_depth
663 ))
664 })?;
665
666 let buffer_stride =
667 u64::try_from(buffer_stride).map_err(|std::num::TryFromIntError { .. }| {
668 Error::Config(format!("buffer_stride too big: {} > u64::MAX", buffer_stride))
669 })?;
670
671 match buffer_stride.checked_mul(num_buffers.into()).map(isize::try_from) {
675 None | Some(Err(std::num::TryFromIntError { .. })) => {
676 return Err(Error::Config(format!(
677 "too much memory required for the buffers: {} * {} > isize::MAX",
678 buffer_stride, num_buffers
679 )));
680 }
681 Some(Ok(_total)) => (),
682 };
683
684 let buffer_stride = NonZeroU64::new(buffer_stride)
685 .ok_or_else(|| Error::Config("buffer_stride is zero".to_owned()))?;
686
687 let min_tx_data = match usize::try_from(*min_tx_buffer_length)
688 .map(|min_tx| (min_tx <= buffer_length).then_some(min_tx))
689 {
690 Ok(Some(min_tx_buffer_length)) => min_tx_buffer_length,
691 Ok(None) | Err(std::num::TryFromIntError { .. }) => {
693 return Err(Error::Config(format!(
694 "buffer_length smaller than minimum TX requirement: {} < {}",
695 buffer_length, *min_tx_buffer_length
696 )));
697 }
698 };
699
700 let mut options = netdev::SessionFlags::empty();
701 options.set(netdev::SessionFlags::RECEIVE_RX_POWER_LEASES, watch_rx_leases);
702
703 let page_size = u64::from(zx::system_get_page_size());
704 let min_tx_buffers = u16::try_from(std::cmp::max(1, page_size / buffer_stride.get()))
705 .map_err(|TryFromIntError { .. }| Error::Config("Too many Tx buffers".to_owned()))?;
706
707 let tx_vmos = if multi_vmo {
708 let mut tx_vmos = Vec::new();
709 let mut current_buffers = min_tx_buffers;
710 let mut total_allocated = 0u16;
711 let mut vmo_id = 1;
712 while total_allocated < *tx_depth {
713 let num_buffers = std::cmp::min(current_buffers, *tx_depth - total_allocated);
714 tx_vmos.push(TxVmoConfig { vmo_id, num_buffers });
715 total_allocated += num_buffers;
716 vmo_id += 1;
717 if vmo_id > 2 {
718 current_buffers *= 2;
719 }
720 }
721 tx_vmos
722 } else {
723 vec![TxVmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: *tx_depth }]
724 };
725
726 Ok(Config {
727 buffer_stride,
728 num_rx_buffers,
729 tx_vmos,
730 options,
731 buffer_layout: BufferLayout {
732 length: buffer_length,
733 min_tx_head: *min_tx_buffer_head,
734 min_tx_tail: *min_tx_buffer_tail,
735 min_tx_data,
736 },
737 buffer_usage_sample_interval,
738 })
739 }
740}
741
742#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
744pub struct Port {
745 pub(crate) base: u8,
746 pub(crate) salt: u8,
747}
748
749impl TryFrom<netdev::PortId> for Port {
750 type Error = Error;
751 fn try_from(netdev::PortId { base, salt }: netdev::PortId) -> Result<Self> {
752 if base <= netdev::MAX_PORTS {
753 Ok(Self { base, salt })
754 } else {
755 Err(Error::InvalidPortId(base))
756 }
757 }
758}
759
760impl From<Port> for netdev::PortId {
761 fn from(Port { base, salt }: Port) -> Self {
762 Self { base, salt }
763 }
764}
765
766struct Pending<K: AllocKind> {
768 storage: Vec<DescId<K>>,
769 waker: Option<Waker>,
770}
771
772impl<K: AllocKind> Pending<K> {
773 fn new(descs: Vec<DescId<K>>) -> Self {
774 Self { storage: descs, waker: None }
775 }
776
777 fn extend(&mut self, descs: impl IntoIterator<Item = DescId<K>>) {
779 let Self { storage, waker } = self;
780 storage.extend(descs);
781 if let Some(waker) = waker.take() {
782 waker.wake();
783 }
784 }
785
786 fn poll_submit(
792 &mut self,
793 fifo: &fasync::Fifo<DescId<K>>,
794 cx: &mut Context<'_>,
795 ) -> Poll<Result<usize>> {
796 let Self { storage, waker } = self;
797 if storage.is_empty() {
798 if waker.as_ref().is_none_or(|waker| !waker.will_wake(cx.waker())) {
799 *waker = Some(cx.waker().clone());
800 }
801 return Poll::Pending;
802 }
803
804 let submitted = ready!(fifo.try_write(cx, &storage[..]))
809 .map_err(|status| Error::Fifo("write", K::REFL.as_str(), status))?
810 .get();
811 let _drained = storage.drain(0..submitted);
812 Poll::Ready(Ok(submitted))
813 }
814}
815
816pub struct RxReadyStorage {
820 inner: ReadyStorage<DescId<Rx>>,
821}
822
823impl RxReadyStorage {
824 pub fn new(capacity: usize) -> Self {
827 Self { inner: ReadyStorage::new(capacity) }
828 }
829
830 fn poll_fifo(
831 &mut self,
832 cx: &mut Context<'_>,
833 fifo: &fasync::Fifo<DescId<Rx>>,
834 ) -> Poll<std::result::Result<(), zx::Status>> {
835 let Self { inner } = self;
836 inner.poll_fifo(cx, fifo)
837 }
838
839 fn drain(&mut self) -> Drain<'_, DescId<Rx>> {
840 let Self { inner } = self;
841 inner.drain()
842 }
843}
844
845pub(in crate::session) struct ReadyStorage<T> {
850 data: Box<[MaybeUninit<T>]>,
856 available: Range<usize>,
857}
858
859impl<T> Drop for ReadyStorage<T> {
860 fn drop(&mut self) {
861 let _ = self.drain();
862 }
863}
864
865struct Drain<'a, T> {
866 ready: &'a mut ReadyStorage<T>,
867}
868
869impl<'a, T> Iterator for Drain<'a, T> {
870 type Item = T;
871
872 fn next(&mut self) -> Option<Self::Item> {
873 let Self { ready: ReadyStorage { data, available: Range { start, end } } } = self;
874 if start != end {
875 let desc = std::mem::replace(&mut data[*start], MaybeUninit::uninit());
876 *start += 1;
877 Some(unsafe { desc.assume_init() })
880 } else {
881 None
882 }
883 }
884}
885
886impl<'a, T> Drop for Drain<'a, T> {
887 fn drop(&mut self) {
888 let Self { ready: ReadyStorage { data, available } } = self;
889 let range = available.clone();
890 for initialized in &mut data[range] {
893 unsafe { initialized.assume_init_drop() }
896 }
897 *available = 0..0;
898 }
899}
900
901impl<T> ReadyStorage<T> {
902 pub(crate) fn new(capacity: usize) -> Self {
903 let data = std::iter::from_fn(|| Some(MaybeUninit::uninit())).take(capacity).collect();
904 Self { data, available: 0..0 }
905 }
906
907 fn poll_fifo(
908 &mut self,
909 cx: &mut Context<'_>,
910 fifo: &fasync::Fifo<T>,
911 ) -> Poll<std::result::Result<(), zx::Status>>
912 where
913 T: fasync::FifoEntry,
914 {
915 let Self { data, available: Range { start, end } } = self;
916 if *start == *end {
917 let count: NonZeroUsize = ready!(fifo.try_read(cx, &mut data[..]))?;
918 *start = 0;
919 *end = count.get();
920 }
921 Poll::Ready(Ok(()))
922 }
923
924 fn drain(&mut self) -> Drain<'_, T> {
927 Drain { ready: self }
928 }
929}
930
931struct TxIdleListeners {
932 event: event_listener::Event,
933 tx_in_flight: AtomicUsize,
934}
935
936impl TxIdleListeners {
937 fn new() -> Self {
938 Self { event: event_listener::Event::new(), tx_in_flight: AtomicUsize::new(0) }
939 }
940
941 fn tx_complete(&self, count: usize) {
945 let Self { event, tx_in_flight } = self;
946 let old_value = tx_in_flight.fetch_sub(count, atomic::Ordering::SeqCst);
947 debug_assert!(old_value >= count);
948 if old_value == count {
949 let _notified: usize = event.notify(usize::MAX);
950 }
951 }
952
953 fn tx_started(&self) {
955 let Self { event: _, tx_in_flight } = self;
956 let _: usize = tx_in_flight.fetch_add(1, atomic::Ordering::SeqCst);
957 }
958
959 async fn wait(&self) {
960 let Self { event, tx_in_flight } = self;
961 loop {
970 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
971 return;
972 }
973
974 event_listener::listener!(event => listener);
975
976 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
977 return;
978 }
979
980 listener.await;
981 }
982 }
983}
984
985#[derive(Debug)]
991pub struct RxLease {
992 handle: netdev::DelegatedRxLeaseHandle,
993}
994
995impl Drop for RxLease {
996 fn drop(&mut self) {
997 let Self { handle } = self;
998 match handle {
1001 netdev::DelegatedRxLeaseHandle::Channel(_channel) => {
1002 }
1004 netdev::DelegatedRxLeaseHandle::Eventpair(_eventpair) => {
1005 }
1007 netdev::DelegatedRxLeaseHandle::__SourceBreaking { .. } => {}
1008 }
1009 }
1010}
1011
1012impl RxLease {
1013 pub fn inner(&self) -> &netdev::DelegatedRxLeaseHandle {
1015 &self.handle
1016 }
1017}
1018
1019#[cfg(test)]
1020mod tests {
1021 use super::*;
1022 use std::num::NonZeroU32;
1023 use std::ops::Deref;
1024 use std::sync::Arc;
1025 use std::task::Poll;
1026
1027 use assert_matches::assert_matches;
1028 use fuchsia_async::Fifo;
1029 use test_case::test_case;
1030 use zerocopy::{FromBytes, Immutable, IntoBytes};
1031
1032 use crate::session::DerivableConfig;
1033
1034 use super::buffer::{
1035 AllocKind, DescId, NETWORK_DEVICE_DESCRIPTOR_LENGTH, NETWORK_DEVICE_DESCRIPTOR_VERSION,
1036 };
1037 use super::{
1038 BufferLayout, BufferUsageEstimator, Config, DeviceBaseInfo, DeviceInfo, Error, Inner,
1039 Mutex, Pool, ReadyStorage, Task, TxIdleListeners, TxState,
1040 };
1041
1042 impl Inner {
1043 pub(super) fn new_test(
1044 pool: Arc<Pool>,
1045 proxy: netdev::SessionProxy,
1046 name: String,
1047 rx: Fifo<DescId<Rx>>,
1048 tx: Fifo<DescId<Tx>>,
1049 num_rx_buffers: usize,
1050 tx_ready: Mutex<ReadyStorage<DescId<Tx>>>,
1051 tx_idle_listeners: TxIdleListeners,
1052 tx_state: Mutex<TxState>,
1053 ) -> Self {
1054 Self {
1055 pool,
1056 proxy,
1057 name,
1058 rx,
1059 tx,
1060 num_rx_buffers,
1061 tx_ready,
1062 tx_idle_listeners,
1063 tx_state,
1064 }
1065 }
1066
1067 pub(super) fn tx_state(&self) -> &Mutex<TxState> {
1068 &self.tx_state
1069 }
1070
1071 pub(super) fn pool(&self) -> &Arc<Pool> {
1072 &self.pool
1073 }
1074 }
1075
1076 impl Task {
1077 pub(super) fn new_test(
1078 inner: Arc<Inner>,
1079 sample_interval: Option<std::time::Duration>,
1080 ) -> Self {
1081 let buffer_usage_sampler = sample_interval
1082 .map(|i| (fasync::Interval::new(i.into()), BufferUsageEstimator::new()));
1083 Self { inner, buffer_usage_sampler }
1084 }
1085 }
1086
1087 pub(super) const DEFAULT_DEVICE_BASE_INFO: DeviceBaseInfo = DeviceBaseInfo {
1088 rx_depth: 1,
1089 tx_depth: 1,
1090 buffer_alignment: 1,
1091 max_buffer_length: None,
1092 min_rx_buffer_length: 0,
1093 min_tx_buffer_head: 0,
1094 min_tx_buffer_length: 0,
1095 min_tx_buffer_tail: 0,
1096 max_buffer_parts: fidl_fuchsia_hardware_network::MAX_DESCRIPTOR_CHAIN,
1097 min_rx_buffers: None,
1098 };
1099
1100 pub(super) const DEFAULT_DEVICE_INFO: DeviceInfo = DeviceInfo {
1101 min_descriptor_length: 0,
1102 descriptor_version: 1,
1103 base_info: DEFAULT_DEVICE_BASE_INFO,
1104 };
1105
1106 const DEFAULT_BUFFER_LENGTH: usize = 2048;
1107
1108 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1109 min_descriptor_length: u8::MAX,
1110 ..DEFAULT_DEVICE_INFO
1111 }, format!("descriptor length too small: {} < {}", NETWORK_DEVICE_DESCRIPTOR_LENGTH, u8::MAX))]
1112 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1113 descriptor_version: 42,
1114 ..DEFAULT_DEVICE_INFO
1115 }, format!("descriptor version mismatch: {} != {}", NETWORK_DEVICE_DESCRIPTOR_VERSION, 42))]
1116 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1117 base_info: DeviceBaseInfo {
1118 tx_depth: 0,
1119 ..DEFAULT_DEVICE_BASE_INFO
1120 },
1121 ..DEFAULT_DEVICE_INFO
1122 }, "no TX buffers")]
1123 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1124 base_info: DeviceBaseInfo {
1125 rx_depth: 0,
1126 ..DEFAULT_DEVICE_BASE_INFO
1127 },
1128 ..DEFAULT_DEVICE_INFO
1129 }, "no RX buffers")]
1130 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1131 base_info: DeviceBaseInfo {
1132 tx_depth: u16::MAX,
1133 rx_depth: u16::MAX,
1134 ..DEFAULT_DEVICE_BASE_INFO
1135 },
1136 ..DEFAULT_DEVICE_INFO
1137 }, format!("too many buffers requested: {} + {} > u16::MAX", u16::MAX, u16::MAX))]
1138 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1139 base_info: DeviceBaseInfo {
1140 min_tx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1141 ..DEFAULT_DEVICE_BASE_INFO
1142 },
1143 ..DEFAULT_DEVICE_INFO
1144 }, format!(
1145 "buffer_length smaller than minimum TX requirement: {} < {}",
1146 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1147 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1148 base_info: DeviceBaseInfo {
1149 min_tx_buffer_head: DEFAULT_BUFFER_LENGTH as u16 + 1,
1150 ..DEFAULT_DEVICE_BASE_INFO
1151 },
1152 ..DEFAULT_DEVICE_INFO
1153 }, format!(
1154 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/0",
1155 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1156 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1157 base_info: DeviceBaseInfo {
1158 min_tx_buffer_tail: DEFAULT_BUFFER_LENGTH as u16 + 1,
1159 ..DEFAULT_DEVICE_BASE_INFO
1160 },
1161 ..DEFAULT_DEVICE_INFO
1162 }, format!(
1163 "buffer length {} does not meet minimum tx buffer head/tail requirement 0/{}",
1164 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1165 #[test_case(0, DEFAULT_DEVICE_INFO, "buffer_stride is zero")]
1166 #[test_case(usize::MAX, DEFAULT_DEVICE_INFO,
1167 format!(
1168 "too much memory required for the buffers: {} * {} > isize::MAX",
1169 usize::MAX, 2))]
1170 #[test_case(usize::MAX, DeviceInfo {
1171 base_info: DeviceBaseInfo {
1172 buffer_alignment: 2,
1173 ..DEFAULT_DEVICE_BASE_INFO
1174 },
1175 ..DEFAULT_DEVICE_INFO
1176 }, format!(
1177 "not possible to align {} to {} under usize::MAX",
1178 usize::MAX, 2))]
1179 fn configs_from_device_info_err(
1180 buffer_length: usize,
1181 info: DeviceInfo,
1182 expected: impl Deref<Target = str>,
1183 ) {
1184 let config = DerivableConfig { default_buffer_length: buffer_length, ..Default::default() };
1185 assert_matches!(
1186 info.make_config(config),
1187 Err(Error::Config(got)) if got.as_str() == expected.deref()
1188 );
1189 }
1190
1191 #[test_case(DeviceInfo {
1192 base_info: DeviceBaseInfo {
1193 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1194 ..DEFAULT_DEVICE_BASE_INFO
1195 },
1196 ..DEFAULT_DEVICE_INFO
1197 }, DEFAULT_BUFFER_LENGTH + 1; "default below min")]
1198 #[test_case(DeviceInfo {
1199 base_info: DeviceBaseInfo {
1200 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 - 1),
1201 ..DEFAULT_DEVICE_BASE_INFO
1202 },
1203 ..DEFAULT_DEVICE_INFO
1204 }, DEFAULT_BUFFER_LENGTH - 1; "default above max")]
1205 #[test_case(DeviceInfo {
1206 base_info: DeviceBaseInfo {
1207 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 - 1,
1208 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 + 1),
1209 ..DEFAULT_DEVICE_BASE_INFO
1210 },
1211 ..DEFAULT_DEVICE_INFO
1212 }, DEFAULT_BUFFER_LENGTH; "default in bounds")]
1213 fn configs_from_device_buffer_length(info: DeviceInfo, expected_length: usize) {
1214 let config = info
1215 .make_config(DerivableConfig {
1216 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1217 ..Default::default()
1218 })
1219 .expect("is valid");
1220 let Config {
1221 buffer_layout: BufferLayout { length, min_tx_data: _, min_tx_head: _, min_tx_tail: _ },
1222 buffer_stride: _,
1223 num_rx_buffers: _,
1224 tx_vmos: _,
1225 options: _,
1226 buffer_usage_sample_interval: _,
1227 } = config;
1228 assert_eq!(length, expected_length);
1229 }
1230
1231 pub(super) fn make_fifos<K: AllocKind>() -> (Fifo<DescId<K>>, zx::Fifo<DescId<K>>) {
1232 let (handle, other_end) = zx::Fifo::create(256).unwrap();
1233 (Fifo::from_fifo(handle), other_end)
1234 }
1235
1236 fn remove_rights<T: FromBytes + IntoBytes + Immutable>(
1237 fifo: Fifo<T>,
1238 rights_to_remove: zx::Rights,
1239 ) -> Fifo<T> {
1240 let fifo = zx::Fifo::from(fifo);
1241 let rights = fifo.as_handle_ref().basic_info().expect("can retrieve info").rights;
1242
1243 let fifo = fifo.replace_handle(rights ^ rights_to_remove).expect("can replace");
1244 Fifo::from_fifo(fifo)
1245 }
1246
1247 enum TxOrRx {
1248 Tx,
1249 Rx,
1250 }
1251 #[test_case(TxOrRx::Tx, zx::Rights::READ; "tx read")]
1252 #[test_case(TxOrRx::Tx, zx::Rights::WRITE; "tx write")]
1253 #[test_case(TxOrRx::Rx, zx::Rights::WRITE; "rx read")]
1254 #[fuchsia::test]
1255 async fn task_as_future_poll_error(which_fifo: TxOrRx, right_to_remove: zx::Rights) {
1256 let config = DEFAULT_DEVICE_INFO
1264 .make_config(DerivableConfig {
1265 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1266 ..Default::default()
1267 })
1268 .expect("is valid");
1269 let CreatedPool { pool, descriptors_vmo: _descriptors_vmo, data_vmos: _data_vmos } =
1270 Pool::new(config).expect("is valid");
1271 let (session_proxy, _session_server) =
1272 fidl::endpoints::create_proxy::<fidl_fuchsia_hardware_network::SessionMarker>();
1273
1274 let (rx, _rx_sender) = make_fifos();
1275 let (tx, _tx_receiver) = make_fifos();
1276
1277 let (tx, rx) = match which_fifo {
1279 TxOrRx::Tx => (remove_rights(tx, right_to_remove), rx),
1280 TxOrRx::Rx => (tx, remove_rights(rx, right_to_remove)),
1281 };
1282
1283 let tx_state = Mutex::new(TxState::new(vec![]));
1284
1285 let buf = pool.alloc_tx_buffer(1).await.expect("can allocate");
1286 let inner = Arc::new(Inner {
1287 pool,
1288 proxy: session_proxy,
1289 name: "fake_task".to_string(),
1290 rx,
1291 tx,
1292 num_rx_buffers: 10,
1293 tx_ready: Mutex::new(ReadyStorage::new(10)),
1294 tx_idle_listeners: TxIdleListeners::new(),
1295 tx_state,
1296 });
1297
1298 inner.send(buf);
1299
1300 let task = Task { inner, buffer_usage_sampler: None };
1301 futures::pin_mut!(task);
1302
1303 assert_matches!(futures::poll!(task.as_mut()), Poll::Ready(Err(Error::Fifo(_, _, _))));
1306 }
1307
1308 #[test_case(1; "drain first")]
1309 #[test_case(2; "drain first two")]
1310 #[test_case(3; "drain all")]
1311 #[fuchsia::test]
1312 async fn ready_storage_batch_iterator(drain_first_n: usize) {
1313 let (handle, fifo_server) = zx::Fifo::<u32>::create(256).unwrap();
1314 let fifo_client = Fifo::from_fifo(handle);
1315 let items = vec![10u32, 20u32, 30u32];
1316 let written = fifo_server.write(&items[..]).expect("write to fifo");
1317 assert_eq!(written.get(), 3);
1318
1319 let mut ready_storage = ReadyStorage::<u32>::new(10);
1320
1321 poll_fn(|cx| ready_storage.poll_fifo(cx, &fifo_client)).await.expect("fetch from fifo");
1323
1324 let mut drain = ready_storage.drain();
1325 for i in 0..drain_first_n {
1326 assert_eq!(drain.next(), Some(items[i]));
1327 }
1328 if drain_first_n == items.len() {
1329 assert_eq!(drain.next(), None);
1330 }
1331 std::mem::drop(drain);
1334
1335 let fetch_fut = poll_fn(|cx| ready_storage.poll_fifo(cx, &fifo_client));
1338 futures::pin_mut!(fetch_fut);
1339 assert_matches!(futures::poll!(fetch_fut), Poll::Pending);
1340 }
1341}