1mod buffer;
8mod tx;
9
10use std::fmt::Debug;
11use std::mem::MaybeUninit;
12use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, 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 async fn recv(&self) -> Result<Buffer<Rx>> {
82 self.inner.recv().await
83 }
84
85 pub async fn alloc_tx_buffer(&self, num_bytes: usize) -> Result<Buffer<Tx>> {
89 self.inner.pool.alloc_tx_buffer(num_bytes).await
90 }
91
92 pub fn try_alloc_single_part_tx_buffer(
97 &self,
98 num_bytes: usize,
99 ) -> Result<Option<SinglePartTxBuffer>> {
100 self.inner.pool.try_alloc_single_part_tx_buffer(num_bytes)
101 }
102
103 pub async fn alloc_tx_buffers(
116 &self,
117 num_bytes: usize,
118 ) -> Result<impl Iterator<Item = Result<Buffer<Tx>>> + '_> {
119 self.inner.pool.alloc_tx_buffers(num_bytes).await
120 }
121
122 pub async fn attach(&self, port: Port, rx_frames: &[netdev::FrameType]) -> Result<()> {
124 let fut = self.inner.proxy.attach(&port.into(), rx_frames);
131 let () = fut.await?.map_err(|raw| Error::Attach(port, zx::Status::from_raw(raw)))?;
132 Ok(())
133 }
134
135 pub async fn detach(&self, port: Port) -> Result<()> {
137 let () = self
138 .inner
139 .proxy
140 .detach(&port.into())
141 .await?
142 .map_err(|raw| Error::Detach(port, zx::Status::from_raw(raw)))?;
143 Ok(())
144 }
145
146 pub async fn wait_tx_idle(&self) {
159 self.inner.tx_idle_listeners.wait().await;
160 }
161
162 pub fn watch_rx_leases(&self) -> impl Stream<Item = Result<RxLease>> + Send + Sync + use<> {
177 let inner = Arc::clone(&self.inner);
178 let watcher = RxLeaseWatcher::new(Arc::clone(&inner.pool));
179 futures::stream::try_unfold((inner, watcher), |(inner, mut watcher)| async move {
180 let DelegatedRxLease {
181 hold_until_frame,
182 handle,
183 __source_breaking: fidl::marker::SourceBreaking,
184 } = match inner.proxy.watch_delegated_rx_lease().await {
185 Ok(lease) => lease,
186 Err(e) => {
187 if e.is_closed() {
188 return Ok(None);
189 } else {
190 return Err(Error::Fidl(e));
191 }
192 }
193 };
194 let hold_until_frame = hold_until_frame.ok_or(Error::InvalidLease)?;
195 let handle = RxLease { handle: handle.ok_or(Error::InvalidLease)? };
196
197 watcher.wait_until(hold_until_frame).await;
198 Ok(Some((handle, (inner, watcher))))
199 })
200 }
201
202 pub async fn close(&self) -> Result<()> {
204 self.inner.proxy.close()?;
205 let mut event_stream = self.inner.proxy.take_event_stream();
207 while let Some(event) = event_stream.next().await {
208 match event {
209 Err(fidl::Error::ClientChannelClosed { .. }) => break,
210 Ok(_) => {} Err(e) => return Err(Error::Fidl(e)),
212 }
213 }
214 Ok(())
215 }
216}
217
218struct Inner {
219 pool: Arc<Pool>,
220 proxy: netdev::SessionProxy,
221 name: String,
222 rx: fasync::Fifo<DescId<Rx>>,
223 tx: fasync::Fifo<DescId<Tx>>,
224 rx_ready: Mutex<ReadyBuffer<DescId<Rx>>>,
225 tx_ready: Mutex<ReadyBuffer<DescId<Tx>>>,
226 tx_idle_listeners: TxIdleListeners,
227 tx_state: Mutex<TxState>,
228}
229
230impl Inner {
231 async fn new(device: &netdev::DeviceProxy, name: &str, config: Config) -> Result<Arc<Self>> {
233 let CreatedPool { pool, descriptors_vmo, data_vmos } = Pool::new(config.clone())?;
234 let tx_vmo_cumulative_buffers = {
235 let mut cumulative = 0u16;
236 config
237 .tx_vmos
238 .iter()
239 .map(|vmo_config| {
240 cumulative += vmo_config.num_buffers;
241 cumulative
242 })
243 .collect::<Vec<_>>()
244 };
245 let tx_state = Mutex::new(TxState::new(tx_vmo_cumulative_buffers));
246
247 let session_info = {
248 let descriptor_length =
251 u8::try_from(NETWORK_DEVICE_DESCRIPTOR_LENGTH / std::mem::size_of::<u64>())
252 .expect("descriptor length in 64-bit words not representable by u8");
253 let data = data_vmos
254 .into_iter()
255 .enumerate()
256 .map(|(idx, vmo)| {
257 let vmo_id = netdev::VmoId::try_from(idx).expect("invalid vmo id");
258 let num_rx_buffers =
259 if vmo_id == DEFAULT_VMO_ID { config.num_rx_buffers.get() } else { 0 };
260 fidl_fuchsia_hardware_network::DataVmo {
261 id: Some(vmo_id),
262 vmo: Some(vmo),
263 num_rx_buffers: Some(num_rx_buffers),
264 __source_breaking: fidl::marker::SourceBreaking,
265 }
266 })
267 .collect::<Vec<_>>();
268 netdev::SessionInfo {
269 descriptors: Some(descriptors_vmo),
270 data: Some(data),
271 descriptor_version: Some(NETWORK_DEVICE_DESCRIPTOR_VERSION),
272 descriptor_length: Some(descriptor_length),
273 descriptor_count: Some(config.num_tx_buffers().get() + config.num_rx_buffers.get()),
274 options: Some(config.options),
275 ..Default::default()
276 }
277 };
278
279 let (client, netdev::Fifos { rx, tx }) = device
280 .open_session(name, session_info)
281 .await?
282 .map_err(|raw| Error::Open(name.to_owned(), zx::Status::from_raw(raw)))?;
283 let proxy = client.into_proxy();
284
285 let rx = fasync::Fifo::from_fifo(rx);
286 let tx = fasync::Fifo::from_fifo(tx);
287
288 let vmos_to_register = if pool.has_decommittable_tx_vmo() {
289 &pool.decommittable_tx_vmo_ids[0..=0]
291 } else {
292 &[DEFAULT_VMO_ID]
293 };
294 let (s, status) = proxy.register_for_tx(vmos_to_register).await.map_err(Error::Fidl)?;
295 zx::Status::ok(status).map_err(Error::RegisterForTx)?;
296 assert_eq!(s, 1);
297
298 Ok(Arc::new(Self {
299 pool,
300 proxy,
301 name: name.to_owned(),
302 rx,
303 tx,
304 rx_ready: Mutex::new(ReadyBuffer::new(config.num_rx_buffers.get().into())),
305 tx_ready: Mutex::new(ReadyBuffer::new(config.num_tx_buffers().get().into())),
306 tx_idle_listeners: TxIdleListeners::new(),
307 tx_state,
308 }))
309 }
310
311 fn poll_submit_rx(&self, cx: &mut Context<'_>) -> Poll<Result<usize>> {
315 self.pool.rx_pending.lock().poll_submit(&self.rx, cx)
316 }
317
318 fn poll_complete_rx(&self, cx: &mut Context<'_>) -> Poll<Result<DescId<Rx>>> {
322 let mut rx_ready = self.rx_ready.lock();
323 rx_ready.poll_with_fifo(cx, &self.rx).map_err(|status| Error::Fifo("read", "rx", status))
324 }
325
326 fn poll_submit_tx(&self, cx: &mut Context<'_>) -> Poll<Result<usize>> {
330 self.tx_state.lock().poll_submit_tx(&self.proxy, &self.pool, &self.tx, cx)
331 }
332
333 fn poll_complete_tx(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
335 let result = {
336 let mut tx_ready = self.tx_ready.lock();
337 tx_ready.poll_with_fifo(cx, &self.tx).map(|r| match r {
341 Ok(desc) => self.pool.tx_completed(desc),
342 Err(status) => Err(Error::Fifo("read", "tx", status)),
343 })
344 };
345
346 match &result {
347 Poll::Ready(Ok(())) => self.tx_idle_listeners.tx_complete(),
348 Poll::Pending | Poll::Ready(Err(_)) => {}
349 }
350 result
351 }
352
353 fn send(&self, buffer: Buffer<Tx>) {
360 self.tx_idle_listeners.tx_started();
361 let mut state = self.tx_state.lock();
362 state.send(&self.proxy, &self.pool, buffer);
363 }
364
365 async fn recv(&self) -> Result<Buffer<Rx>> {
369 poll_fn(|cx| -> Poll<Result<Buffer<Rx>>> {
370 let head = ready!(self.poll_complete_rx(cx))?;
371 Poll::Ready(self.pool.rx_completed(head))
372 })
373 .await
374 }
375}
376
377#[must_use = "futures do nothing unless you `.await` or poll them"]
381pub struct Task {
382 inner: Arc<Inner>,
383 buffer_usage_sampler: Option<(fasync::Interval, BufferUsageEstimator)>,
384}
385
386impl Future for Task {
387 type Output = Result<()>;
388 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
389 let this = self.as_mut().get_mut();
390 let inner = &*this.inner;
391 loop {
392 let mut all_pending = true;
393
394 while inner.poll_complete_tx(cx)?.is_ready_checked::<()>() {
397 all_pending = false;
398 }
399 if inner.poll_submit_rx(cx)?.is_ready_checked::<usize>() {
400 all_pending = false;
401 }
402 if inner.poll_submit_tx(cx)?.is_ready_checked::<usize>() {
403 all_pending = false;
404 }
405
406 if !all_pending {
407 continue;
408 }
409
410 if let Some((interval, estimator)) = &mut this.buffer_usage_sampler {
411 while interval.poll_next_unpin(cx).is_ready_checked::<Option<()>>() {
412 let buffer_usage_estimate = {
413 let mut state = inner.pool.tx_alloc_state.lock();
414 estimator.update(state.sample_peak_buffer_usage())
415 };
416 if inner.tx_state.lock().attempt_unregister(
417 buffer_usage_estimate,
418 &inner.proxy,
419 &inner.pool,
420 ) {
421 all_pending = false;
422 }
423 }
424 }
425
426 if all_pending {
427 return Poll::Pending;
428 }
429 }
430 }
431}
432
433#[derive(Debug, Clone)]
435pub struct Config {
436 buffer_stride: NonZeroU64,
438 num_rx_buffers: NonZeroU16,
440 tx_vmos: Vec<TxVmoConfig>,
442 options: netdev::SessionFlags,
444 buffer_layout: BufferLayout,
446 buffer_usage_sample_interval: std::time::Duration,
447}
448
449impl Config {
450 pub fn num_tx_buffers(&self) -> NonZeroU16 {
452 let sum: u16 = self.tx_vmos.iter().map(|v| v.num_buffers).sum();
453 NonZeroU16::new(sum).expect("num_tx_buffers is zero")
454 }
455}
456
457#[derive(Debug, Clone, Copy)]
459struct BufferLayout {
460 min_tx_data: usize,
462 min_tx_head: u16,
464 min_tx_tail: u16,
466 length: usize,
468}
469
470#[derive(Debug, Clone, ValidFidlTable)]
472#[fidl_table_src(netdev::DeviceBaseInfo)]
473#[fidl_table_strict]
474pub struct DeviceBaseInfo {
475 pub rx_depth: u16,
477 pub tx_depth: u16,
479 pub buffer_alignment: u32,
481 #[fidl_field_type(optional)]
483 pub max_buffer_length: Option<NonZeroU32>,
484 pub min_rx_buffer_length: u32,
486 pub min_tx_buffer_length: u32,
488 pub min_tx_buffer_head: u16,
490 pub min_tx_buffer_tail: u16,
492 pub max_buffer_parts: u8,
494 #[fidl_field_type(optional)]
497 pub min_rx_buffers: Option<NonZeroU16>,
498}
499
500#[derive(Debug, Clone, ValidFidlTable)]
502#[fidl_table_src(netdev::DeviceInfo)]
503#[fidl_table_strict]
504pub struct DeviceInfo {
505 pub min_descriptor_length: u8,
507 pub descriptor_version: u8,
509 pub base_info: DeviceBaseInfo,
511}
512
513#[derive(Debug, Copy, Clone)]
516pub struct DerivableConfig {
517 pub default_buffer_length: usize,
519 pub watch_rx_leases: bool,
521 pub multi_vmo: bool,
523 pub buffer_usage_sample_interval: std::time::Duration,
525}
526
527impl DerivableConfig {
528 pub const DEFAULT_BUFFER_LENGTH: usize = 2048;
535 pub const DEFAULT: Self = Self {
537 default_buffer_length: Self::DEFAULT_BUFFER_LENGTH,
538 watch_rx_leases: false,
539 multi_vmo: false,
540 buffer_usage_sample_interval: std::time::Duration::from_secs(1),
541 };
542}
543
544impl Default for DerivableConfig {
545 fn default() -> Self {
546 Self::DEFAULT
547 }
548}
549
550impl DeviceInfo {
551 pub fn make_config(&self, config: DerivableConfig) -> Result<Config> {
556 let DeviceInfo {
557 min_descriptor_length,
558 descriptor_version,
559 base_info:
560 DeviceBaseInfo {
561 rx_depth,
562 tx_depth,
563 buffer_alignment,
564 max_buffer_length,
565 min_rx_buffer_length,
566 min_tx_buffer_length,
567 min_tx_buffer_head,
568 min_tx_buffer_tail,
569 max_buffer_parts: _,
570 min_rx_buffers: _,
571 },
572 } = self;
573 if NETWORK_DEVICE_DESCRIPTOR_VERSION != *descriptor_version {
574 return Err(Error::Config(format!(
575 "descriptor version mismatch: {} != {}",
576 NETWORK_DEVICE_DESCRIPTOR_VERSION, descriptor_version
577 )));
578 }
579 if NETWORK_DEVICE_DESCRIPTOR_LENGTH < usize::from(*min_descriptor_length) {
580 return Err(Error::Config(format!(
581 "descriptor length too small: {} < {}",
582 NETWORK_DEVICE_DESCRIPTOR_LENGTH, min_descriptor_length
583 )));
584 }
585
586 let DerivableConfig {
587 default_buffer_length,
588 watch_rx_leases,
589 multi_vmo,
590 buffer_usage_sample_interval,
591 } = config;
592
593 let num_rx_buffers =
594 NonZeroU16::new(*rx_depth).ok_or_else(|| Error::Config("no RX buffers".to_owned()))?;
595 if *tx_depth == 0 {
596 return Err(Error::Config("no TX buffers".to_owned()));
597 }
598
599 let max_buffer_length = max_buffer_length
600 .and_then(|max| {
601 usize::try_from(max.get()).ok_checked::<TryFromIntError>()
605 })
606 .unwrap_or(usize::MAX);
607 let min_buffer_length = usize::try_from(*min_rx_buffer_length)
608 .ok_checked::<TryFromIntError>()
609 .unwrap_or(usize::MAX);
610
611 let buffer_length =
612 usize::min(max_buffer_length, usize::max(min_buffer_length, default_buffer_length));
613
614 let buffer_alignment = usize::try_from(*buffer_alignment).map_err(
615 |std::num::TryFromIntError { .. }| {
616 Error::Config(format!(
617 "buffer_alignment not representable within usize: {}",
618 buffer_alignment,
619 ))
620 },
621 )?;
622
623 let buffer_stride = buffer_length
624 .checked_add(buffer_alignment - 1)
625 .map(|x| x / buffer_alignment * buffer_alignment)
626 .ok_or_else(|| {
627 Error::Config(format!(
628 "not possible to align {} to {} under usize::MAX",
629 buffer_length, buffer_alignment,
630 ))
631 })?;
632
633 if buffer_stride < buffer_length {
634 return Err(Error::Config(format!(
635 "buffer stride too small {} < {}",
636 buffer_stride, buffer_length
637 )));
638 }
639
640 if buffer_length < usize::from(*min_tx_buffer_head) + usize::from(*min_tx_buffer_tail) {
641 return Err(Error::Config(format!(
642 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/{}",
643 buffer_length, min_tx_buffer_head, min_tx_buffer_tail,
644 )));
645 }
646
647 let num_buffers =
648 rx_depth.checked_add(*tx_depth).filter(|num| *num != u16::MAX).ok_or_else(|| {
649 Error::Config(format!(
650 "too many buffers requested: {} + {} > u16::MAX",
651 rx_depth, tx_depth
652 ))
653 })?;
654
655 let buffer_stride =
656 u64::try_from(buffer_stride).map_err(|std::num::TryFromIntError { .. }| {
657 Error::Config(format!("buffer_stride too big: {} > u64::MAX", buffer_stride))
658 })?;
659
660 match buffer_stride.checked_mul(num_buffers.into()).map(isize::try_from) {
664 None | Some(Err(std::num::TryFromIntError { .. })) => {
665 return Err(Error::Config(format!(
666 "too much memory required for the buffers: {} * {} > isize::MAX",
667 buffer_stride, num_buffers
668 )));
669 }
670 Some(Ok(_total)) => (),
671 };
672
673 let buffer_stride = NonZeroU64::new(buffer_stride)
674 .ok_or_else(|| Error::Config("buffer_stride is zero".to_owned()))?;
675
676 let min_tx_data = match usize::try_from(*min_tx_buffer_length)
677 .map(|min_tx| (min_tx <= buffer_length).then_some(min_tx))
678 {
679 Ok(Some(min_tx_buffer_length)) => min_tx_buffer_length,
680 Ok(None) | Err(std::num::TryFromIntError { .. }) => {
682 return Err(Error::Config(format!(
683 "buffer_length smaller than minimum TX requirement: {} < {}",
684 buffer_length, *min_tx_buffer_length
685 )));
686 }
687 };
688
689 let mut options = netdev::SessionFlags::empty();
690 options.set(netdev::SessionFlags::RECEIVE_RX_POWER_LEASES, watch_rx_leases);
691
692 let page_size = u64::from(zx::system_get_page_size());
693 let min_tx_buffers = u16::try_from(std::cmp::max(1, page_size / buffer_stride.get()))
694 .map_err(|TryFromIntError { .. }| Error::Config("Too many Tx buffers".to_owned()))?;
695
696 let tx_vmos = if multi_vmo {
697 let mut tx_vmos = Vec::new();
698 let mut current_buffers = min_tx_buffers;
699 let mut total_allocated = 0u16;
700 let mut vmo_id = 1;
701 while total_allocated < *tx_depth {
702 let num_buffers = std::cmp::min(current_buffers, *tx_depth - total_allocated);
703 tx_vmos.push(TxVmoConfig { vmo_id, num_buffers });
704 total_allocated += num_buffers;
705 vmo_id += 1;
706 if vmo_id > 2 {
707 current_buffers *= 2;
708 }
709 }
710 tx_vmos
711 } else {
712 vec![TxVmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: *tx_depth }]
713 };
714
715 Ok(Config {
716 buffer_stride,
717 num_rx_buffers,
718 tx_vmos,
719 options,
720 buffer_layout: BufferLayout {
721 length: buffer_length,
722 min_tx_head: *min_tx_buffer_head,
723 min_tx_tail: *min_tx_buffer_tail,
724 min_tx_data,
725 },
726 buffer_usage_sample_interval,
727 })
728 }
729}
730
731#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
733pub struct Port {
734 pub(crate) base: u8,
735 pub(crate) salt: u8,
736}
737
738impl TryFrom<netdev::PortId> for Port {
739 type Error = Error;
740 fn try_from(netdev::PortId { base, salt }: netdev::PortId) -> Result<Self> {
741 if base <= netdev::MAX_PORTS {
742 Ok(Self { base, salt })
743 } else {
744 Err(Error::InvalidPortId(base))
745 }
746 }
747}
748
749impl From<Port> for netdev::PortId {
750 fn from(Port { base, salt }: Port) -> Self {
751 Self { base, salt }
752 }
753}
754
755struct Pending<K: AllocKind> {
757 storage: Vec<DescId<K>>,
758 waker: Option<Waker>,
759}
760
761impl<K: AllocKind> Pending<K> {
762 fn new(descs: Vec<DescId<K>>) -> Self {
763 Self { storage: descs, waker: None }
764 }
765
766 fn extend(&mut self, descs: impl IntoIterator<Item = DescId<K>>) {
768 let Self { storage, waker } = self;
769 storage.extend(descs);
770 if let Some(waker) = waker.take() {
771 waker.wake();
772 }
773 }
774
775 fn poll_submit(
781 &mut self,
782 fifo: &fasync::Fifo<DescId<K>>,
783 cx: &mut Context<'_>,
784 ) -> Poll<Result<usize>> {
785 let Self { storage, waker } = self;
786 if storage.is_empty() {
787 if waker.as_ref().is_none_or(|waker| !waker.will_wake(cx.waker())) {
788 *waker = Some(cx.waker().clone());
789 }
790 return Poll::Pending;
791 }
792
793 let submitted = ready!(fifo.try_write(cx, &storage[..]))
798 .map_err(|status| Error::Fifo("write", K::REFL.as_str(), status))?;
799 let _drained = storage.drain(0..submitted);
800 Poll::Ready(Ok(submitted))
801 }
802}
803
804struct ReadyBuffer<T> {
811 data: Vec<MaybeUninit<T>>,
817 available: Range<usize>,
818}
819
820impl<T> Drop for ReadyBuffer<T> {
821 fn drop(&mut self) {
822 let Self { data, available } = self;
823 for initialized in &mut data[available.clone()] {
824 unsafe { initialized.assume_init_drop() }
827 }
828 *available = 0..0;
829 }
830}
831
832impl<T> ReadyBuffer<T> {
833 fn new(capacity: usize) -> Self {
834 let data = std::iter::from_fn(|| Some(MaybeUninit::uninit())).take(capacity).collect();
835 Self { data, available: 0..0 }
836 }
837
838 fn poll_with_fifo(
839 &mut self,
840 cx: &mut Context<'_>,
841 fifo: &fuchsia_async::Fifo<T>,
842 ) -> Poll<std::result::Result<T, zx::Status>>
843 where
844 T: fasync::FifoEntry,
845 {
846 let Self { data, available: Range { start, end } } = self;
847
848 loop {
849 if *start != *end {
851 let desc = std::mem::replace(&mut data[*start], MaybeUninit::uninit());
852 *start += 1;
853 let desc = unsafe { desc.assume_init() };
856 return Poll::Ready(Ok(desc));
857 }
858 let count = ready!(fifo.try_read(cx, &mut data[..]))?;
860 *start = 0;
861 *end = count;
862 }
863 }
864}
865
866struct TxIdleListeners {
867 event: event_listener::Event,
868 tx_in_flight: AtomicUsize,
869}
870
871impl TxIdleListeners {
872 fn new() -> Self {
873 Self { event: event_listener::Event::new(), tx_in_flight: AtomicUsize::new(0) }
874 }
875
876 fn tx_complete(&self) {
880 let Self { event, tx_in_flight } = self;
881 let old_value = tx_in_flight.fetch_sub(1, atomic::Ordering::SeqCst);
882 debug_assert_ne!(old_value, 0);
883 if old_value == 1 {
884 let _notified: usize = event.notify(usize::MAX);
885 }
886 }
887
888 fn tx_started(&self) {
890 let Self { event: _, tx_in_flight } = self;
891 let _: usize = tx_in_flight.fetch_add(1, atomic::Ordering::SeqCst);
892 }
893
894 async fn wait(&self) {
895 let Self { event, tx_in_flight } = self;
896 loop {
905 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
906 return;
907 }
908
909 event_listener::listener!(event => listener);
910
911 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
912 return;
913 }
914
915 listener.await;
916 }
917 }
918}
919
920#[derive(Debug)]
926pub struct RxLease {
927 handle: netdev::DelegatedRxLeaseHandle,
928}
929
930impl Drop for RxLease {
931 fn drop(&mut self) {
932 let Self { handle } = self;
933 match handle {
936 netdev::DelegatedRxLeaseHandle::Channel(_channel) => {
937 }
939 netdev::DelegatedRxLeaseHandle::Eventpair(_eventpair) => {
940 }
942 netdev::DelegatedRxLeaseHandle::__SourceBreaking { .. } => {}
943 }
944 }
945}
946
947impl RxLease {
948 pub fn inner(&self) -> &netdev::DelegatedRxLeaseHandle {
950 &self.handle
951 }
952}
953
954#[cfg(test)]
955mod tests {
956 use super::*;
957 use std::num::NonZeroU32;
958 use std::ops::Deref;
959 use std::sync::Arc;
960 use std::task::Poll;
961
962 use assert_matches::assert_matches;
963 use fuchsia_async::Fifo;
964 use test_case::test_case;
965 use zerocopy::{FromBytes, Immutable, IntoBytes};
966
967 use crate::session::DerivableConfig;
968
969 use super::buffer::{
970 AllocKind, DescId, NETWORK_DEVICE_DESCRIPTOR_LENGTH, NETWORK_DEVICE_DESCRIPTOR_VERSION,
971 };
972 use super::{
973 BufferLayout, BufferUsageEstimator, Config, DeviceBaseInfo, DeviceInfo, Error, Inner,
974 Mutex, Pool, ReadyBuffer, Task, TxIdleListeners, TxState,
975 };
976
977 impl Inner {
978 pub(super) fn new_test(
979 pool: Arc<Pool>,
980 proxy: netdev::SessionProxy,
981 name: String,
982 rx: Fifo<DescId<Rx>>,
983 tx: Fifo<DescId<Tx>>,
984 rx_ready: Mutex<ReadyBuffer<DescId<Rx>>>,
985 tx_ready: Mutex<ReadyBuffer<DescId<Tx>>>,
986 tx_idle_listeners: TxIdleListeners,
987 tx_state: Mutex<TxState>,
988 ) -> Self {
989 Self { pool, proxy, name, rx, tx, rx_ready, tx_ready, tx_idle_listeners, tx_state }
990 }
991
992 pub(super) fn tx_state(&self) -> &Mutex<TxState> {
993 &self.tx_state
994 }
995
996 pub(super) fn pool(&self) -> &Arc<Pool> {
997 &self.pool
998 }
999 }
1000
1001 impl Task {
1002 pub(super) fn new_test(
1003 inner: Arc<Inner>,
1004 sample_interval: Option<std::time::Duration>,
1005 ) -> Self {
1006 let buffer_usage_sampler = sample_interval
1007 .map(|i| (fasync::Interval::new(i.into()), BufferUsageEstimator::new()));
1008 Self { inner, buffer_usage_sampler }
1009 }
1010 }
1011
1012 pub(super) const DEFAULT_DEVICE_BASE_INFO: DeviceBaseInfo = DeviceBaseInfo {
1013 rx_depth: 1,
1014 tx_depth: 1,
1015 buffer_alignment: 1,
1016 max_buffer_length: None,
1017 min_rx_buffer_length: 0,
1018 min_tx_buffer_head: 0,
1019 min_tx_buffer_length: 0,
1020 min_tx_buffer_tail: 0,
1021 max_buffer_parts: fidl_fuchsia_hardware_network::MAX_DESCRIPTOR_CHAIN,
1022 min_rx_buffers: None,
1023 };
1024
1025 pub(super) const DEFAULT_DEVICE_INFO: DeviceInfo = DeviceInfo {
1026 min_descriptor_length: 0,
1027 descriptor_version: 1,
1028 base_info: DEFAULT_DEVICE_BASE_INFO,
1029 };
1030
1031 const DEFAULT_BUFFER_LENGTH: usize = 2048;
1032
1033 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1034 min_descriptor_length: u8::MAX,
1035 ..DEFAULT_DEVICE_INFO
1036 }, format!("descriptor length too small: {} < {}", NETWORK_DEVICE_DESCRIPTOR_LENGTH, u8::MAX))]
1037 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1038 descriptor_version: 42,
1039 ..DEFAULT_DEVICE_INFO
1040 }, format!("descriptor version mismatch: {} != {}", NETWORK_DEVICE_DESCRIPTOR_VERSION, 42))]
1041 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1042 base_info: DeviceBaseInfo {
1043 tx_depth: 0,
1044 ..DEFAULT_DEVICE_BASE_INFO
1045 },
1046 ..DEFAULT_DEVICE_INFO
1047 }, "no TX buffers")]
1048 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1049 base_info: DeviceBaseInfo {
1050 rx_depth: 0,
1051 ..DEFAULT_DEVICE_BASE_INFO
1052 },
1053 ..DEFAULT_DEVICE_INFO
1054 }, "no RX buffers")]
1055 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1056 base_info: DeviceBaseInfo {
1057 tx_depth: u16::MAX,
1058 rx_depth: u16::MAX,
1059 ..DEFAULT_DEVICE_BASE_INFO
1060 },
1061 ..DEFAULT_DEVICE_INFO
1062 }, format!("too many buffers requested: {} + {} > u16::MAX", u16::MAX, u16::MAX))]
1063 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1064 base_info: DeviceBaseInfo {
1065 min_tx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1066 ..DEFAULT_DEVICE_BASE_INFO
1067 },
1068 ..DEFAULT_DEVICE_INFO
1069 }, format!(
1070 "buffer_length smaller than minimum TX requirement: {} < {}",
1071 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1072 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1073 base_info: DeviceBaseInfo {
1074 min_tx_buffer_head: DEFAULT_BUFFER_LENGTH as u16 + 1,
1075 ..DEFAULT_DEVICE_BASE_INFO
1076 },
1077 ..DEFAULT_DEVICE_INFO
1078 }, format!(
1079 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/0",
1080 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1081 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1082 base_info: DeviceBaseInfo {
1083 min_tx_buffer_tail: DEFAULT_BUFFER_LENGTH as u16 + 1,
1084 ..DEFAULT_DEVICE_BASE_INFO
1085 },
1086 ..DEFAULT_DEVICE_INFO
1087 }, format!(
1088 "buffer length {} does not meet minimum tx buffer head/tail requirement 0/{}",
1089 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1090 #[test_case(0, DEFAULT_DEVICE_INFO, "buffer_stride is zero")]
1091 #[test_case(usize::MAX, DEFAULT_DEVICE_INFO,
1092 format!(
1093 "too much memory required for the buffers: {} * {} > isize::MAX",
1094 usize::MAX, 2))]
1095 #[test_case(usize::MAX, DeviceInfo {
1096 base_info: DeviceBaseInfo {
1097 buffer_alignment: 2,
1098 ..DEFAULT_DEVICE_BASE_INFO
1099 },
1100 ..DEFAULT_DEVICE_INFO
1101 }, format!(
1102 "not possible to align {} to {} under usize::MAX",
1103 usize::MAX, 2))]
1104 fn configs_from_device_info_err(
1105 buffer_length: usize,
1106 info: DeviceInfo,
1107 expected: impl Deref<Target = str>,
1108 ) {
1109 let config = DerivableConfig { default_buffer_length: buffer_length, ..Default::default() };
1110 assert_matches!(
1111 info.make_config(config),
1112 Err(Error::Config(got)) if got.as_str() == expected.deref()
1113 );
1114 }
1115
1116 #[test_case(DeviceInfo {
1117 base_info: DeviceBaseInfo {
1118 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1119 ..DEFAULT_DEVICE_BASE_INFO
1120 },
1121 ..DEFAULT_DEVICE_INFO
1122 }, DEFAULT_BUFFER_LENGTH + 1; "default below min")]
1123 #[test_case(DeviceInfo {
1124 base_info: DeviceBaseInfo {
1125 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 - 1),
1126 ..DEFAULT_DEVICE_BASE_INFO
1127 },
1128 ..DEFAULT_DEVICE_INFO
1129 }, DEFAULT_BUFFER_LENGTH - 1; "default above max")]
1130 #[test_case(DeviceInfo {
1131 base_info: DeviceBaseInfo {
1132 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 - 1,
1133 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 + 1),
1134 ..DEFAULT_DEVICE_BASE_INFO
1135 },
1136 ..DEFAULT_DEVICE_INFO
1137 }, DEFAULT_BUFFER_LENGTH; "default in bounds")]
1138 fn configs_from_device_buffer_length(info: DeviceInfo, expected_length: usize) {
1139 let config = info
1140 .make_config(DerivableConfig {
1141 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1142 ..Default::default()
1143 })
1144 .expect("is valid");
1145 let Config {
1146 buffer_layout: BufferLayout { length, min_tx_data: _, min_tx_head: _, min_tx_tail: _ },
1147 buffer_stride: _,
1148 num_rx_buffers: _,
1149 tx_vmos: _,
1150 options: _,
1151 buffer_usage_sample_interval: _,
1152 } = config;
1153 assert_eq!(length, expected_length);
1154 }
1155
1156 pub(super) fn make_fifos<K: AllocKind>() -> (Fifo<DescId<K>>, zx::Fifo<DescId<K>>) {
1157 let (handle, other_end) = zx::Fifo::create(256).unwrap();
1158 (Fifo::from_fifo(handle), other_end)
1159 }
1160
1161 fn remove_rights<T: FromBytes + IntoBytes + Immutable>(
1162 fifo: Fifo<T>,
1163 rights_to_remove: zx::Rights,
1164 ) -> Fifo<T> {
1165 let fifo = zx::Fifo::from(fifo);
1166 let rights = fifo.as_handle_ref().basic_info().expect("can retrieve info").rights;
1167
1168 let fifo = fifo.replace_handle(rights ^ rights_to_remove).expect("can replace");
1169 Fifo::from_fifo(fifo)
1170 }
1171
1172 enum TxOrRx {
1173 Tx,
1174 Rx,
1175 }
1176 #[test_case(TxOrRx::Tx, zx::Rights::READ; "tx read")]
1177 #[test_case(TxOrRx::Tx, zx::Rights::WRITE; "tx write")]
1178 #[test_case(TxOrRx::Rx, zx::Rights::WRITE; "rx read")]
1179 #[fuchsia_async::run_singlethreaded(test)]
1180 async fn task_as_future_poll_error(which_fifo: TxOrRx, right_to_remove: zx::Rights) {
1181 let config = DEFAULT_DEVICE_INFO
1189 .make_config(DerivableConfig {
1190 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1191 ..Default::default()
1192 })
1193 .expect("is valid");
1194 let CreatedPool { pool, descriptors_vmo: _descriptors_vmo, data_vmos: _data_vmos } =
1195 Pool::new(config).expect("is valid");
1196 let (session_proxy, _session_server) =
1197 fidl::endpoints::create_proxy::<fidl_fuchsia_hardware_network::SessionMarker>();
1198
1199 let (rx, _rx_sender) = make_fifos();
1200 let (tx, _tx_receiver) = make_fifos();
1201
1202 let (tx, rx) = match which_fifo {
1204 TxOrRx::Tx => (remove_rights(tx, right_to_remove), rx),
1205 TxOrRx::Rx => (tx, remove_rights(rx, right_to_remove)),
1206 };
1207
1208 let tx_state = Mutex::new(TxState::new(vec![]));
1209
1210 let buf = pool.alloc_tx_buffer(1).await.expect("can allocate");
1211 let inner = Arc::new(Inner {
1212 pool,
1213 proxy: session_proxy,
1214 name: "fake_task".to_string(),
1215 rx,
1216 tx,
1217 rx_ready: Mutex::new(ReadyBuffer::new(10)),
1218 tx_ready: Mutex::new(ReadyBuffer::new(10)),
1219 tx_idle_listeners: TxIdleListeners::new(),
1220 tx_state,
1221 });
1222
1223 inner.send(buf);
1224
1225 let task = Task { inner, buffer_usage_sampler: None };
1226 futures::pin_mut!(task);
1227
1228 assert_matches!(futures::poll!(task.as_mut()), Poll::Ready(Err(Error::Fifo(_, _, _))));
1231 }
1232}