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};
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 ExactSizeIterator<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::err_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::err_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::new(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 = config
272 .rx_vmos
273 .iter()
274 .find(|v| v.vmo_id == vmo_id)
275 .map(|v| v.num_buffers)
276 .unwrap_or(0);
277 fidl_fuchsia_hardware_network::DataVmo {
278 id: Some(vmo_id),
279 vmo: Some(vmo),
280 num_rx_buffers: Some(num_rx_buffers),
281 __source_breaking: fidl::marker::SourceBreaking,
282 }
283 })
284 .collect::<Vec<_>>();
285 netdev::SessionInfo {
286 descriptors: Some(descriptors_vmo),
287 data: Some(data),
288 descriptor_version: Some(NETWORK_DEVICE_DESCRIPTOR_VERSION),
289 descriptor_length: Some(descriptor_length),
290 descriptor_count: Some(
291 config.num_tx_buffers().get() + config.num_rx_buffers().get(),
292 ),
293 options: Some(config.options),
294 ..Default::default()
295 }
296 };
297
298 let (client, netdev::Fifos { rx, tx }) = device
299 .open_session(name, session_info)
300 .await?
301 .map_err(|raw| Error::Open(name.to_owned(), zx::Status::err_from_raw(raw)))?;
302 let proxy = client.into_proxy();
303
304 let rx = fasync::Fifo::from_fifo(rx);
305 let tx = fasync::Fifo::from_fifo(tx);
306
307 let vmos_to_register = if pool.has_decommittable_tx_vmo() {
308 &pool.decommittable_tx_vmo_ids[0..=0]
310 } else {
311 &[DEFAULT_VMO_ID]
312 };
313 let (s, status) = proxy.register_for_tx(vmos_to_register).await.map_err(Error::Fidl)?;
314 zx::Status::ok(status).map_err(Error::RegisterForTx)?;
315 assert_eq!(s, 1);
316
317 let num_rx_buffers = config.num_rx_buffers().get().into();
318
319 Ok(Arc::new(Self {
320 pool,
321 proxy,
322 name: name.to_owned(),
323 rx,
324 tx,
325 num_rx_buffers,
326 tx_ready: Mutex::new(ReadyStorage::new(config.num_tx_buffers().get().into())),
327 tx_idle_listeners: TxIdleListeners::new(),
328 tx_state,
329 }))
330 }
331
332 fn poll_submit_rx(&self, cx: &mut Context<'_>) -> Poll<Result<usize>> {
336 self.pool.rx_pending.lock().poll_submit(&self.rx, cx)
337 }
338
339 fn poll_submit_tx(&self, cx: &mut Context<'_>) -> Poll<Result<usize>> {
343 self.tx_state.lock().poll_submit_tx(&self.proxy, &self.pool, &self.tx, cx)
344 }
345
346 fn poll_complete_tx(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
348 let (count, result) = {
349 let mut tx_ready = self.tx_ready.lock();
350 ready!(tx_ready.poll_fifo(cx, &self.tx))
351 .map_err(|status| Error::Fifo("read", "tx", status))?;
352 tx_ready
356 .drain()
357 .try_fold(0, |count, desc| match self.pool.tx_completed(desc) {
358 Ok(()) => Ok(count + 1),
359 Err(e) => Err((count, e)),
360 })
361 .map_or_else(|(count, e)| (count, Err(e)), |count| (count, Ok(())))
362 };
363 self.tx_idle_listeners.tx_complete(count);
364 result?;
365 Poll::Ready(Ok(()))
366 }
367
368 fn send(&self, buffer: Buffer<Tx>) {
375 self.tx_idle_listeners.tx_started();
376 let mut state = self.tx_state.lock();
377 state.send(&self.proxy, &self.pool, buffer);
378 }
379
380 async fn recv<'a>(
384 &'a self,
385 ready_storage: &'a mut RxReadyStorage,
386 ) -> Result<impl ExactSizeIterator<Item = Result<Buffer<Rx>>> + 'a> {
387 poll_fn(|cx| ready_storage.poll_fifo(cx, &self.rx))
388 .await
389 .map_err(|status| Error::Fifo("read", "rx", status))?;
390 Ok(ready_storage.drain().map(move |head| self.pool.rx_completed(head)))
391 }
392}
393
394#[must_use = "futures do nothing unless you `.await` or poll them"]
398pub struct Task {
399 inner: Arc<Inner>,
400 buffer_usage_sampler: Option<(fasync::Interval, BufferUsageEstimator)>,
401}
402
403impl Future for Task {
404 type Output = Result<()>;
405 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
406 let this = self.as_mut().get_mut();
407 let inner = &*this.inner;
408 loop {
409 let mut all_pending = true;
410
411 while inner.poll_complete_tx(cx)?.is_ready_checked::<()>() {
414 all_pending = false;
415 }
416 if inner.poll_submit_rx(cx)?.is_ready_checked::<usize>() {
417 all_pending = false;
418 }
419 if inner.poll_submit_tx(cx)?.is_ready_checked::<usize>() {
420 all_pending = false;
421 }
422
423 if !all_pending {
424 continue;
425 }
426
427 if let Some((interval, estimator)) = &mut this.buffer_usage_sampler {
428 while interval.poll_next_unpin(cx).is_ready_checked::<Option<()>>() {
429 let buffer_usage_estimate = {
430 let mut state = inner.pool.tx_alloc_state.lock();
431 estimator.update(state.sample_peak_buffer_usage())
432 };
433 if inner.tx_state.lock().attempt_unregister(
434 buffer_usage_estimate,
435 &inner.proxy,
436 &inner.pool,
437 ) {
438 all_pending = false;
439 }
440 }
441 }
442
443 if all_pending {
444 return Poll::Pending;
445 }
446 }
447 }
448}
449
450#[derive(Debug, Clone, Copy, PartialEq, Eq)]
452pub(crate) struct VmoConfig {
453 pub(crate) vmo_id: netdev::VmoId,
455 pub(crate) num_buffers: u16,
457}
458
459#[derive(Debug, Clone)]
461pub struct Config {
462 buffer_stride: NonZeroU64,
464 rx_vmos: Vec<VmoConfig>,
466 tx_vmos: Vec<VmoConfig>,
468 options: netdev::SessionFlags,
470 buffer_layout: BufferLayout,
472 buffer_usage_sample_interval: std::time::Duration,
473}
474
475impl Config {
476 pub fn num_rx_buffers(&self) -> NonZeroU16 {
478 let sum: u16 = self.rx_vmos.iter().map(|v| v.num_buffers).sum();
479 NonZeroU16::new(sum).expect("num_rx_buffers is zero")
480 }
481
482 pub fn num_tx_buffers(&self) -> NonZeroU16 {
484 let sum: u16 = self.tx_vmos.iter().map(|v| v.num_buffers).sum();
485 NonZeroU16::new(sum).expect("num_tx_buffers is zero")
486 }
487}
488
489#[derive(Debug, Clone, Copy)]
491struct BufferLayout {
492 min_tx_data: usize,
494 min_tx_head: u16,
496 min_tx_tail: u16,
498 length: usize,
500}
501
502#[derive(Debug, Clone, ValidFidlTable)]
504#[fidl_table_src(netdev::DeviceBaseInfo)]
505#[fidl_table_strict]
506pub struct DeviceBaseInfo {
507 pub rx_depth: u16,
509 pub tx_depth: u16,
511 pub buffer_alignment: u32,
513 #[fidl_field_type(optional)]
515 pub max_buffer_length: Option<NonZeroU32>,
516 pub min_rx_buffer_length: u32,
518 pub min_tx_buffer_length: u32,
520 pub min_tx_buffer_head: u16,
522 pub min_tx_buffer_tail: u16,
524 pub max_buffer_parts: u8,
526 #[fidl_field_type(optional)]
529 pub min_rx_buffers: Option<NonZeroU16>,
530}
531
532#[derive(Debug, Clone, ValidFidlTable)]
534#[fidl_table_src(netdev::DeviceInfo)]
535#[fidl_table_strict]
536pub struct DeviceInfo {
537 pub min_descriptor_length: u8,
539 pub descriptor_version: u8,
541 pub base_info: DeviceBaseInfo,
543}
544
545#[derive(Debug, Copy, Clone)]
548pub struct DerivableConfig {
549 pub default_buffer_length: usize,
551 pub watch_rx_leases: bool,
553 pub multi_vmo: bool,
555 pub buffer_usage_sample_interval: std::time::Duration,
557}
558
559impl DerivableConfig {
560 pub const DEFAULT_BUFFER_LENGTH: usize = 2048;
567 pub const DEFAULT: Self = Self {
569 default_buffer_length: Self::DEFAULT_BUFFER_LENGTH,
570 watch_rx_leases: false,
571 multi_vmo: false,
572 buffer_usage_sample_interval: std::time::Duration::from_secs(1),
573 };
574}
575
576impl Default for DerivableConfig {
577 fn default() -> Self {
578 Self::DEFAULT
579 }
580}
581
582impl DeviceInfo {
583 pub fn make_config(&self, config: DerivableConfig) -> Result<Config> {
588 let DeviceInfo {
589 min_descriptor_length,
590 descriptor_version,
591 base_info:
592 DeviceBaseInfo {
593 rx_depth,
594 tx_depth,
595 buffer_alignment,
596 max_buffer_length,
597 min_rx_buffer_length,
598 min_tx_buffer_length,
599 min_tx_buffer_head,
600 min_tx_buffer_tail,
601 max_buffer_parts: _,
602 min_rx_buffers,
603 },
604 } = self;
605 if NETWORK_DEVICE_DESCRIPTOR_VERSION != *descriptor_version {
606 return Err(Error::Config(format!(
607 "descriptor version mismatch: {} != {}",
608 NETWORK_DEVICE_DESCRIPTOR_VERSION, descriptor_version
609 )));
610 }
611 if NETWORK_DEVICE_DESCRIPTOR_LENGTH < usize::from(*min_descriptor_length) {
612 return Err(Error::Config(format!(
613 "descriptor length too small: {} < {}",
614 NETWORK_DEVICE_DESCRIPTOR_LENGTH, min_descriptor_length
615 )));
616 }
617
618 let DerivableConfig {
619 default_buffer_length,
620 watch_rx_leases,
621 multi_vmo,
622 buffer_usage_sample_interval,
623 } = config;
624
625 let num_rx_buffers =
626 NonZeroU16::new(*rx_depth).ok_or_else(|| Error::Config("no RX buffers".to_owned()))?;
627 let num_tx_buffers =
628 NonZeroU16::new(*tx_depth).ok_or_else(|| Error::Config("no TX buffers".to_owned()))?;
629
630 let max_buffer_length = max_buffer_length
631 .and_then(|max| {
632 usize::try_from(max.get()).ok_checked::<TryFromIntError>()
636 })
637 .unwrap_or(usize::MAX);
638 let min_buffer_length = usize::try_from(*min_rx_buffer_length)
639 .ok_checked::<TryFromIntError>()
640 .unwrap_or(usize::MAX);
641
642 let buffer_length =
643 usize::min(max_buffer_length, usize::max(min_buffer_length, default_buffer_length));
644
645 let buffer_alignment = usize::try_from(*buffer_alignment).map_err(
646 |std::num::TryFromIntError { .. }| {
647 Error::Config(format!(
648 "buffer_alignment not representable within usize: {}",
649 buffer_alignment,
650 ))
651 },
652 )?;
653
654 let buffer_stride = buffer_length
655 .checked_add(buffer_alignment - 1)
656 .map(|x| x / buffer_alignment * buffer_alignment)
657 .ok_or_else(|| {
658 Error::Config(format!(
659 "not possible to align {} to {} under usize::MAX",
660 buffer_length, buffer_alignment,
661 ))
662 })?;
663
664 if buffer_stride < buffer_length {
665 return Err(Error::Config(format!(
666 "buffer stride too small {} < {}",
667 buffer_stride, buffer_length
668 )));
669 }
670
671 if buffer_length < usize::from(*min_tx_buffer_head) + usize::from(*min_tx_buffer_tail) {
672 return Err(Error::Config(format!(
673 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/{}",
674 buffer_length, min_tx_buffer_head, min_tx_buffer_tail,
675 )));
676 }
677
678 let num_buffers = num_rx_buffers
679 .get()
680 .checked_add(num_tx_buffers.get())
681 .filter(|num| *num != u16::MAX)
682 .ok_or_else(|| {
683 Error::Config(format!(
684 "too many buffers requested: {} + {} > u16::MAX",
685 num_rx_buffers, num_tx_buffers
686 ))
687 })?;
688
689 let buffer_stride =
690 u64::try_from(buffer_stride).map_err(|std::num::TryFromIntError { .. }| {
691 Error::Config(format!("buffer_stride too big: {} > u64::MAX", buffer_stride))
692 })?;
693
694 match buffer_stride.checked_mul(num_buffers.into()).map(isize::try_from) {
698 None | Some(Err(std::num::TryFromIntError { .. })) => {
699 return Err(Error::Config(format!(
700 "too much memory required for the buffers: {} * {} > isize::MAX",
701 buffer_stride, num_buffers
702 )));
703 }
704 Some(Ok(_total)) => (),
705 };
706
707 let buffer_stride = NonZeroU64::new(buffer_stride)
708 .ok_or_else(|| Error::Config("buffer_stride is zero".to_owned()))?;
709
710 let min_tx_data = match usize::try_from(*min_tx_buffer_length)
711 .map(|min_tx| (min_tx <= buffer_length).then_some(min_tx))
712 {
713 Ok(Some(min_tx_buffer_length)) => min_tx_buffer_length,
714 Ok(None) | Err(std::num::TryFromIntError { .. }) => {
716 return Err(Error::Config(format!(
717 "buffer_length smaller than minimum TX requirement: {} < {}",
718 buffer_length, *min_tx_buffer_length
719 )));
720 }
721 };
722
723 let mut options = netdev::SessionFlags::empty();
724 options.set(netdev::SessionFlags::RECEIVE_RX_POWER_LEASES, watch_rx_leases);
725
726 let page_size = u64::from(zx::system_get_page_size());
727 let min_buffers_per_vmo = u16::try_from(std::cmp::max(1, page_size / buffer_stride.get()))
728 .map_err(|TryFromIntError { .. }| {
729 Error::Config("Too many buffers per VMO".to_owned())
730 })?;
731
732 let allocate_vmos =
733 |total_depth: u16, min_buffers: u16, start_vmo_id: u8| -> Result<Vec<VmoConfig>> {
734 let mut vmos = Vec::new();
735 let mut current_buffers = min_buffers;
736 let mut total_allocated = 0u16;
737 let mut vmo_id = start_vmo_id;
738 let mut vmos_allocated = 0;
739 while total_allocated < total_depth {
740 let num_buffers = std::cmp::min(current_buffers, total_depth - total_allocated);
741 vmos.push(VmoConfig { vmo_id, num_buffers });
742 total_allocated += num_buffers;
743 vmo_id = vmo_id
744 .checked_add(1)
745 .ok_or_else(|| Error::Config("too many vmos".to_string()))?;
746 vmos_allocated += 1;
747 if vmos_allocated > 1 {
748 current_buffers = current_buffers.saturating_mul(2);
749 }
750 }
751 Ok(vmos)
752 };
753
754 let (rx_vmos, tx_vmos) = if multi_vmo {
755 let min_rx_buffers = min_rx_buffers.unwrap_or(num_rx_buffers);
756 let rx_vmos =
757 allocate_vmos(num_rx_buffers.get(), min_rx_buffers.get(), DEFAULT_VMO_ID)?;
758 let next_vmo_id = u8::try_from(rx_vmos.len())
759 .map_err(|_| Error::Config("too many rx vmos".to_string()))?;
760 let tx_vmos = allocate_vmos(num_tx_buffers.get(), min_buffers_per_vmo, next_vmo_id)?;
761 (rx_vmos, tx_vmos)
762 } else {
763 (
764 vec![VmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: num_rx_buffers.get() }],
765 vec![VmoConfig { vmo_id: DEFAULT_VMO_ID, num_buffers: num_tx_buffers.get() }],
766 )
767 };
768
769 Ok(Config {
770 buffer_stride,
771 rx_vmos,
772 tx_vmos,
773 options,
774 buffer_layout: BufferLayout {
775 length: buffer_length,
776 min_tx_head: *min_tx_buffer_head,
777 min_tx_tail: *min_tx_buffer_tail,
778 min_tx_data,
779 },
780 buffer_usage_sample_interval,
781 })
782 }
783}
784
785#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
787pub struct Port {
788 pub(crate) base: u8,
789 pub(crate) salt: u8,
790}
791
792impl TryFrom<netdev::PortId> for Port {
793 type Error = Error;
794 fn try_from(netdev::PortId { base, salt }: netdev::PortId) -> Result<Self> {
795 if base <= netdev::MAX_PORTS {
796 Ok(Self { base, salt })
797 } else {
798 Err(Error::InvalidPortId(base))
799 }
800 }
801}
802
803impl From<Port> for netdev::PortId {
804 fn from(Port { base, salt }: Port) -> Self {
805 Self { base, salt }
806 }
807}
808
809struct Pending<K: AllocKind> {
811 storage: Vec<DescId<K>>,
812 waker: Option<Waker>,
813}
814
815impl<K: AllocKind> Pending<K> {
816 fn new(descs: Vec<DescId<K>>) -> Self {
817 Self { storage: descs, waker: None }
818 }
819
820 fn extend(&mut self, descs: impl IntoIterator<Item = DescId<K>>) {
822 let Self { storage, waker } = self;
823 storage.extend(descs);
824 if let Some(waker) = waker.take() {
825 waker.wake();
826 }
827 }
828
829 fn poll_submit(
835 &mut self,
836 fifo: &fasync::Fifo<DescId<K>>,
837 cx: &mut Context<'_>,
838 ) -> Poll<Result<usize>> {
839 let Self { storage, waker } = self;
840 if storage.is_empty() {
841 if waker.as_ref().is_none_or(|waker| !waker.will_wake(cx.waker())) {
842 *waker = Some(cx.waker().clone());
843 }
844 return Poll::Pending;
845 }
846
847 let submitted = ready!(fifo.try_write(cx, &storage[..]))
852 .map_err(|status| Error::Fifo("write", K::REFL.as_str(), status))?
853 .get();
854 let _drained = storage.drain(0..submitted);
855 Poll::Ready(Ok(submitted))
856 }
857}
858
859pub struct RxReadyStorage {
863 inner: ReadyStorage<DescId<Rx>>,
864}
865
866impl RxReadyStorage {
867 pub fn new(capacity: usize) -> Self {
870 Self { inner: ReadyStorage::new(capacity) }
871 }
872
873 fn poll_fifo(
874 &mut self,
875 cx: &mut Context<'_>,
876 fifo: &fasync::Fifo<DescId<Rx>>,
877 ) -> Poll<std::result::Result<(), zx::Status>> {
878 let Self { inner } = self;
879 inner.poll_fifo(cx, fifo)
880 }
881
882 fn drain(&mut self) -> Drain<'_, DescId<Rx>> {
883 let Self { inner } = self;
884 inner.drain()
885 }
886}
887
888pub(in crate::session) struct ReadyStorage<T> {
893 data: Box<[MaybeUninit<T>]>,
899 available: Range<usize>,
900}
901
902impl<T> Drop for ReadyStorage<T> {
903 fn drop(&mut self) {
904 let _ = self.drain();
905 }
906}
907
908struct Drain<'a, T> {
909 ready: &'a mut ReadyStorage<T>,
910}
911
912impl<'a, T> Iterator for Drain<'a, T> {
913 type Item = T;
914
915 fn next(&mut self) -> Option<Self::Item> {
916 let Self { ready: ReadyStorage { data, available: Range { start, end } } } = self;
917 if start != end {
918 let desc = std::mem::replace(&mut data[*start], MaybeUninit::uninit());
919 *start += 1;
920 Some(unsafe { desc.assume_init() })
923 } else {
924 None
925 }
926 }
927
928 fn size_hint(&self) -> (usize, Option<usize>) {
929 let len = self.ready.available.len();
930 (len, Some(len))
931 }
932}
933
934impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
935
936impl<'a, T> Drop for Drain<'a, T> {
937 fn drop(&mut self) {
938 let Self { ready: ReadyStorage { data, available } } = self;
939 let range = available.clone();
940 for initialized in &mut data[range] {
943 unsafe { initialized.assume_init_drop() }
946 }
947 *available = 0..0;
948 }
949}
950
951impl<T> ReadyStorage<T> {
952 pub(crate) fn new(capacity: usize) -> Self {
953 let data = std::iter::from_fn(|| Some(MaybeUninit::uninit())).take(capacity).collect();
954 Self { data, available: 0..0 }
955 }
956
957 fn poll_fifo(
958 &mut self,
959 cx: &mut Context<'_>,
960 fifo: &fasync::Fifo<T>,
961 ) -> Poll<std::result::Result<(), zx::Status>>
962 where
963 T: fasync::FifoEntry,
964 {
965 let Self { data, available: Range { start, end } } = self;
966 if *start == *end {
967 let count: NonZeroUsize = ready!(fifo.try_read(cx, &mut data[..]))?;
968 *start = 0;
969 *end = count.get();
970 }
971 Poll::Ready(Ok(()))
972 }
973
974 fn drain(&mut self) -> Drain<'_, T> {
977 Drain { ready: self }
978 }
979}
980
981struct TxIdleListeners {
982 event: event_listener::Event,
983 tx_in_flight: AtomicUsize,
984}
985
986impl TxIdleListeners {
987 fn new() -> Self {
988 Self { event: event_listener::Event::new(), tx_in_flight: AtomicUsize::new(0) }
989 }
990
991 fn tx_complete(&self, count: usize) {
995 let Self { event, tx_in_flight } = self;
996 let old_value = tx_in_flight.fetch_sub(count, atomic::Ordering::SeqCst);
997 debug_assert!(old_value >= count);
998 if old_value == count {
999 let _notified: usize = event.notify(usize::MAX);
1000 }
1001 }
1002
1003 fn tx_started(&self) {
1005 let Self { event: _, tx_in_flight } = self;
1006 let _: usize = tx_in_flight.fetch_add(1, atomic::Ordering::SeqCst);
1007 }
1008
1009 async fn wait(&self) {
1010 let Self { event, tx_in_flight } = self;
1011 loop {
1020 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
1021 return;
1022 }
1023
1024 event_listener::listener!(event => listener);
1025
1026 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
1027 return;
1028 }
1029
1030 listener.await;
1031 }
1032 }
1033}
1034
1035#[derive(Debug)]
1041pub struct RxLease {
1042 handle: netdev::DelegatedRxLeaseHandle,
1043}
1044
1045impl Drop for RxLease {
1046 fn drop(&mut self) {
1047 let Self { handle } = self;
1048 match handle {
1051 netdev::DelegatedRxLeaseHandle::Channel(_channel) => {
1052 }
1054 netdev::DelegatedRxLeaseHandle::Eventpair(_eventpair) => {
1055 }
1057 netdev::DelegatedRxLeaseHandle::__SourceBreaking { .. } => {}
1058 }
1059 }
1060}
1061
1062impl RxLease {
1063 pub fn new(handle: netdev::DelegatedRxLeaseHandle) -> Self {
1065 Self { handle }
1066 }
1067
1068 pub fn inner(&self) -> &netdev::DelegatedRxLeaseHandle {
1070 &self.handle
1071 }
1072}
1073
1074impl From<netdev::DelegatedRxLeaseHandle> for RxLease {
1075 fn from(handle: netdev::DelegatedRxLeaseHandle) -> Self {
1076 Self::new(handle)
1077 }
1078}
1079
1080#[cfg(test)]
1081mod tests {
1082 use super::*;
1083 use std::num::NonZeroU32;
1084 use std::ops::Deref;
1085 use std::sync::Arc;
1086 use std::task::Poll;
1087
1088 use assert_matches::assert_matches;
1089 use fuchsia_async::Fifo;
1090 use test_case::test_case;
1091 use zerocopy::{FromBytes, Immutable, IntoBytes};
1092
1093 use crate::session::DerivableConfig;
1094
1095 use super::buffer::{
1096 AllocKind, DescId, NETWORK_DEVICE_DESCRIPTOR_LENGTH, NETWORK_DEVICE_DESCRIPTOR_VERSION,
1097 };
1098 use super::{
1099 BufferLayout, BufferUsageEstimator, Config, DeviceBaseInfo, DeviceInfo, Error, Inner,
1100 Mutex, Pool, ReadyStorage, Task, TxIdleListeners, TxState,
1101 };
1102
1103 impl Inner {
1104 pub(super) fn new_test(
1105 pool: Arc<Pool>,
1106 proxy: netdev::SessionProxy,
1107 name: String,
1108 rx: Fifo<DescId<Rx>>,
1109 tx: Fifo<DescId<Tx>>,
1110 num_rx_buffers: usize,
1111 tx_ready: Mutex<ReadyStorage<DescId<Tx>>>,
1112 tx_idle_listeners: TxIdleListeners,
1113 tx_state: Mutex<TxState>,
1114 ) -> Self {
1115 Self {
1116 pool,
1117 proxy,
1118 name,
1119 rx,
1120 tx,
1121 num_rx_buffers,
1122 tx_ready,
1123 tx_idle_listeners,
1124 tx_state,
1125 }
1126 }
1127
1128 pub(super) fn tx_state(&self) -> &Mutex<TxState> {
1129 &self.tx_state
1130 }
1131
1132 pub(super) fn pool(&self) -> &Arc<Pool> {
1133 &self.pool
1134 }
1135 }
1136
1137 impl Task {
1138 pub(super) fn new_test(
1139 inner: Arc<Inner>,
1140 sample_interval: Option<std::time::Duration>,
1141 ) -> Self {
1142 let buffer_usage_sampler = sample_interval
1143 .map(|i| (fasync::Interval::new(i.into()), BufferUsageEstimator::new()));
1144 Self { inner, buffer_usage_sampler }
1145 }
1146 }
1147
1148 pub(super) const DEFAULT_DEVICE_BASE_INFO: DeviceBaseInfo = DeviceBaseInfo {
1149 rx_depth: 1,
1150 tx_depth: 1,
1151 buffer_alignment: 1,
1152 max_buffer_length: None,
1153 min_rx_buffer_length: 0,
1154 min_tx_buffer_head: 0,
1155 min_tx_buffer_length: 0,
1156 min_tx_buffer_tail: 0,
1157 max_buffer_parts: fidl_fuchsia_hardware_network::MAX_DESCRIPTOR_CHAIN,
1158 min_rx_buffers: None,
1159 };
1160
1161 pub(super) const DEFAULT_DEVICE_INFO: DeviceInfo = DeviceInfo {
1162 min_descriptor_length: 0,
1163 descriptor_version: 1,
1164 base_info: DEFAULT_DEVICE_BASE_INFO,
1165 };
1166
1167 const DEFAULT_BUFFER_LENGTH: usize = 2048;
1168
1169 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1170 min_descriptor_length: u8::MAX,
1171 ..DEFAULT_DEVICE_INFO
1172 }, format!("descriptor length too small: {} < {}", NETWORK_DEVICE_DESCRIPTOR_LENGTH, u8::MAX))]
1173 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1174 descriptor_version: 42,
1175 ..DEFAULT_DEVICE_INFO
1176 }, format!("descriptor version mismatch: {} != {}", NETWORK_DEVICE_DESCRIPTOR_VERSION, 42))]
1177 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1178 base_info: DeviceBaseInfo {
1179 tx_depth: 0,
1180 ..DEFAULT_DEVICE_BASE_INFO
1181 },
1182 ..DEFAULT_DEVICE_INFO
1183 }, "no TX buffers")]
1184 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1185 base_info: DeviceBaseInfo {
1186 rx_depth: 0,
1187 ..DEFAULT_DEVICE_BASE_INFO
1188 },
1189 ..DEFAULT_DEVICE_INFO
1190 }, "no RX buffers")]
1191 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1192 base_info: DeviceBaseInfo {
1193 tx_depth: u16::MAX,
1194 rx_depth: u16::MAX,
1195 ..DEFAULT_DEVICE_BASE_INFO
1196 },
1197 ..DEFAULT_DEVICE_INFO
1198 }, format!("too many buffers requested: {} + {} > u16::MAX", u16::MAX, u16::MAX))]
1199 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1200 base_info: DeviceBaseInfo {
1201 min_tx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1202 ..DEFAULT_DEVICE_BASE_INFO
1203 },
1204 ..DEFAULT_DEVICE_INFO
1205 }, format!(
1206 "buffer_length smaller than minimum TX requirement: {} < {}",
1207 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1208 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1209 base_info: DeviceBaseInfo {
1210 min_tx_buffer_head: DEFAULT_BUFFER_LENGTH as u16 + 1,
1211 ..DEFAULT_DEVICE_BASE_INFO
1212 },
1213 ..DEFAULT_DEVICE_INFO
1214 }, format!(
1215 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/0",
1216 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1217 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1218 base_info: DeviceBaseInfo {
1219 min_tx_buffer_tail: DEFAULT_BUFFER_LENGTH as u16 + 1,
1220 ..DEFAULT_DEVICE_BASE_INFO
1221 },
1222 ..DEFAULT_DEVICE_INFO
1223 }, format!(
1224 "buffer length {} does not meet minimum tx buffer head/tail requirement 0/{}",
1225 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1226 #[test_case(0, DEFAULT_DEVICE_INFO, "buffer_stride is zero")]
1227 #[test_case(usize::MAX, DEFAULT_DEVICE_INFO,
1228 format!(
1229 "too much memory required for the buffers: {} * {} > isize::MAX",
1230 usize::MAX, 2))]
1231 #[test_case(usize::MAX, DeviceInfo {
1232 base_info: DeviceBaseInfo {
1233 buffer_alignment: 2,
1234 ..DEFAULT_DEVICE_BASE_INFO
1235 },
1236 ..DEFAULT_DEVICE_INFO
1237 }, format!(
1238 "not possible to align {} to {} under usize::MAX",
1239 usize::MAX, 2))]
1240 fn configs_from_device_info_err(
1241 buffer_length: usize,
1242 info: DeviceInfo,
1243 expected: impl Deref<Target = str>,
1244 ) {
1245 let config = DerivableConfig { default_buffer_length: buffer_length, ..Default::default() };
1246 assert_matches!(
1247 info.make_config(config),
1248 Err(Error::Config(got)) if got.as_str() == expected.deref()
1249 );
1250 }
1251
1252 #[test_case(DeviceInfo {
1253 base_info: DeviceBaseInfo {
1254 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1255 ..DEFAULT_DEVICE_BASE_INFO
1256 },
1257 ..DEFAULT_DEVICE_INFO
1258 }, DEFAULT_BUFFER_LENGTH + 1; "default below min")]
1259 #[test_case(DeviceInfo {
1260 base_info: DeviceBaseInfo {
1261 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 - 1),
1262 ..DEFAULT_DEVICE_BASE_INFO
1263 },
1264 ..DEFAULT_DEVICE_INFO
1265 }, DEFAULT_BUFFER_LENGTH - 1; "default above max")]
1266 #[test_case(DeviceInfo {
1267 base_info: DeviceBaseInfo {
1268 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 - 1,
1269 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 + 1),
1270 ..DEFAULT_DEVICE_BASE_INFO
1271 },
1272 ..DEFAULT_DEVICE_INFO
1273 }, DEFAULT_BUFFER_LENGTH; "default in bounds")]
1274 fn configs_from_device_buffer_length(info: DeviceInfo, expected_length: usize) {
1275 let config = info
1276 .make_config(DerivableConfig {
1277 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1278 ..Default::default()
1279 })
1280 .expect("is valid");
1281 let Config {
1282 buffer_layout: BufferLayout { length, min_tx_data: _, min_tx_head: _, min_tx_tail: _ },
1283 buffer_stride: _,
1284 rx_vmos: _,
1285 tx_vmos: _,
1286 options: _,
1287 buffer_usage_sample_interval: _,
1288 } = config;
1289 assert_eq!(length, expected_length);
1290 }
1291
1292 #[test]
1293 fn multi_vmo_allocation_scheme() {
1294 let info = DeviceInfo {
1295 base_info: DeviceBaseInfo { rx_depth: 16, tx_depth: 16, ..DEFAULT_DEVICE_BASE_INFO },
1296 ..DEFAULT_DEVICE_INFO
1297 };
1298 let config = info
1299 .make_config(DerivableConfig { multi_vmo: true, ..Default::default() })
1300 .expect("is valid");
1301 let Config { rx_vmos, tx_vmos, .. } = config;
1302 let expected_rx = vec![VmoConfig { vmo_id: 0, num_buffers: 16 }];
1303 let expected_tx = vec![
1304 VmoConfig { vmo_id: 1, num_buffers: 2 },
1305 VmoConfig { vmo_id: 2, num_buffers: 2 },
1306 VmoConfig { vmo_id: 3, num_buffers: 4 },
1307 VmoConfig { vmo_id: 4, num_buffers: 8 },
1308 ];
1309 assert_eq!(rx_vmos, expected_rx);
1310 assert_eq!(tx_vmos, expected_tx);
1311 }
1312
1313 #[test]
1314 fn multi_vmo_allocation_scheme_with_min_rx_buffers() {
1315 let info = DeviceInfo {
1316 base_info: DeviceBaseInfo {
1317 rx_depth: 16,
1318 tx_depth: 16,
1319 min_rx_buffers: NonZeroU16::new(2),
1320 ..DEFAULT_DEVICE_BASE_INFO
1321 },
1322 ..DEFAULT_DEVICE_INFO
1323 };
1324 let config = info
1325 .make_config(DerivableConfig { multi_vmo: true, ..Default::default() })
1326 .expect("is valid");
1327 let Config { rx_vmos, tx_vmos, .. } = config;
1328 let expected_rx = vec![
1329 VmoConfig { vmo_id: 0, num_buffers: 2 },
1330 VmoConfig { vmo_id: 1, num_buffers: 2 },
1331 VmoConfig { vmo_id: 2, num_buffers: 4 },
1332 VmoConfig { vmo_id: 3, num_buffers: 8 },
1333 ];
1334 let expected_tx = vec![
1335 VmoConfig { vmo_id: 4, num_buffers: 2 },
1336 VmoConfig { vmo_id: 5, num_buffers: 2 },
1337 VmoConfig { vmo_id: 6, num_buffers: 4 },
1338 VmoConfig { vmo_id: 7, num_buffers: 8 },
1339 ];
1340 assert_eq!(rx_vmos, expected_rx);
1341 assert_eq!(tx_vmos, expected_tx);
1342 }
1343
1344 pub(super) fn make_fifos<K: AllocKind>() -> (Fifo<DescId<K>>, zx::Fifo<DescId<K>>) {
1345 let (handle, other_end) = zx::Fifo::create(256).unwrap();
1346 (Fifo::from_fifo(handle), other_end)
1347 }
1348
1349 fn remove_rights<T: FromBytes + IntoBytes + Immutable>(
1350 fifo: Fifo<T>,
1351 rights_to_remove: zx::Rights,
1352 ) -> Fifo<T> {
1353 let fifo = zx::Fifo::from(fifo);
1354 let rights = fifo.as_handle_ref().basic_info().expect("can retrieve info").rights;
1355
1356 let fifo = fifo.replace_handle(rights ^ rights_to_remove).expect("can replace");
1357 Fifo::from_fifo(fifo)
1358 }
1359
1360 enum TxOrRx {
1361 Tx,
1362 Rx,
1363 }
1364 #[test_case(TxOrRx::Tx, zx::Rights::READ; "tx read")]
1365 #[test_case(TxOrRx::Tx, zx::Rights::WRITE; "tx write")]
1366 #[test_case(TxOrRx::Rx, zx::Rights::WRITE; "rx read")]
1367 #[fuchsia::test]
1368 async fn task_as_future_poll_error(which_fifo: TxOrRx, right_to_remove: zx::Rights) {
1369 let config = DEFAULT_DEVICE_INFO
1377 .make_config(DerivableConfig {
1378 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1379 ..Default::default()
1380 })
1381 .expect("is valid");
1382 let CreatedPool { pool, descriptors_vmo: _descriptors_vmo, data_vmos: _data_vmos } =
1383 Pool::new(config).expect("is valid");
1384 let (session_proxy, _session_server) =
1385 fidl::endpoints::create_proxy::<fidl_fuchsia_hardware_network::SessionMarker>();
1386
1387 let (rx, _rx_sender) = make_fifos();
1388 let (tx, _tx_receiver) = make_fifos();
1389
1390 let (tx, rx) = match which_fifo {
1392 TxOrRx::Tx => (remove_rights(tx, right_to_remove), rx),
1393 TxOrRx::Rx => (tx, remove_rights(rx, right_to_remove)),
1394 };
1395
1396 let tx_state = Mutex::new(TxState::new(vec![]));
1397
1398 let buf = pool.alloc_tx_buffer(1).await.expect("can allocate");
1399 let inner = Arc::new(Inner {
1400 pool,
1401 proxy: session_proxy,
1402 name: "fake_task".to_string(),
1403 rx,
1404 tx,
1405 num_rx_buffers: 10,
1406 tx_ready: Mutex::new(ReadyStorage::new(10)),
1407 tx_idle_listeners: TxIdleListeners::new(),
1408 tx_state,
1409 });
1410
1411 inner.send(buf);
1412
1413 let task = Task { inner, buffer_usage_sampler: None };
1414 futures::pin_mut!(task);
1415
1416 assert_matches!(futures::poll!(task.as_mut()), Poll::Ready(Err(Error::Fifo(_, _, _))));
1419 }
1420
1421 #[test_case(1; "drain first")]
1422 #[test_case(2; "drain first two")]
1423 #[test_case(3; "drain all")]
1424 #[fuchsia::test]
1425 async fn ready_storage_batch_iterator(drain_first_n: usize) {
1426 let (handle, fifo_server) = zx::Fifo::<u32>::create(256).unwrap();
1427 let fifo_client = Fifo::from_fifo(handle);
1428 let items = vec![10u32, 20u32, 30u32];
1429 let written = fifo_server.write(&items[..]).expect("write to fifo");
1430 assert_eq!(written.get(), 3);
1431
1432 let mut ready_storage = ReadyStorage::<u32>::new(10);
1433
1434 poll_fn(|cx| ready_storage.poll_fifo(cx, &fifo_client)).await.expect("fetch from fifo");
1436
1437 let mut drain = ready_storage.drain();
1438 for i in 0..drain_first_n {
1439 assert_eq!(drain.next(), Some(items[i]));
1440 }
1441 if drain_first_n == items.len() {
1442 assert_eq!(drain.next(), None);
1443 }
1444 std::mem::drop(drain);
1447
1448 let fetch_fut = poll_fn(|cx| ready_storage.poll_fifo(cx, &fifo_client));
1451 futures::pin_mut!(fetch_fut);
1452 assert_matches!(futures::poll!(fetch_fut), Poll::Pending);
1453 }
1454}