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 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::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 { 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 = 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 Iterator<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
929impl<'a, T> Drop for Drain<'a, T> {
930 fn drop(&mut self) {
931 let Self { ready: ReadyStorage { data, available } } = self;
932 let range = available.clone();
933 for initialized in &mut data[range] {
936 unsafe { initialized.assume_init_drop() }
939 }
940 *available = 0..0;
941 }
942}
943
944impl<T> ReadyStorage<T> {
945 pub(crate) fn new(capacity: usize) -> Self {
946 let data = std::iter::from_fn(|| Some(MaybeUninit::uninit())).take(capacity).collect();
947 Self { data, available: 0..0 }
948 }
949
950 fn poll_fifo(
951 &mut self,
952 cx: &mut Context<'_>,
953 fifo: &fasync::Fifo<T>,
954 ) -> Poll<std::result::Result<(), zx::Status>>
955 where
956 T: fasync::FifoEntry,
957 {
958 let Self { data, available: Range { start, end } } = self;
959 if *start == *end {
960 let count: NonZeroUsize = ready!(fifo.try_read(cx, &mut data[..]))?;
961 *start = 0;
962 *end = count.get();
963 }
964 Poll::Ready(Ok(()))
965 }
966
967 fn drain(&mut self) -> Drain<'_, T> {
970 Drain { ready: self }
971 }
972}
973
974struct TxIdleListeners {
975 event: event_listener::Event,
976 tx_in_flight: AtomicUsize,
977}
978
979impl TxIdleListeners {
980 fn new() -> Self {
981 Self { event: event_listener::Event::new(), tx_in_flight: AtomicUsize::new(0) }
982 }
983
984 fn tx_complete(&self, count: usize) {
988 let Self { event, tx_in_flight } = self;
989 let old_value = tx_in_flight.fetch_sub(count, atomic::Ordering::SeqCst);
990 debug_assert!(old_value >= count);
991 if old_value == count {
992 let _notified: usize = event.notify(usize::MAX);
993 }
994 }
995
996 fn tx_started(&self) {
998 let Self { event: _, tx_in_flight } = self;
999 let _: usize = tx_in_flight.fetch_add(1, atomic::Ordering::SeqCst);
1000 }
1001
1002 async fn wait(&self) {
1003 let Self { event, tx_in_flight } = self;
1004 loop {
1013 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
1014 return;
1015 }
1016
1017 event_listener::listener!(event => listener);
1018
1019 if tx_in_flight.load(atomic::Ordering::SeqCst) == 0 {
1020 return;
1021 }
1022
1023 listener.await;
1024 }
1025 }
1026}
1027
1028#[derive(Debug)]
1034pub struct RxLease {
1035 handle: netdev::DelegatedRxLeaseHandle,
1036}
1037
1038impl Drop for RxLease {
1039 fn drop(&mut self) {
1040 let Self { handle } = self;
1041 match handle {
1044 netdev::DelegatedRxLeaseHandle::Channel(_channel) => {
1045 }
1047 netdev::DelegatedRxLeaseHandle::Eventpair(_eventpair) => {
1048 }
1050 netdev::DelegatedRxLeaseHandle::__SourceBreaking { .. } => {}
1051 }
1052 }
1053}
1054
1055impl RxLease {
1056 pub fn inner(&self) -> &netdev::DelegatedRxLeaseHandle {
1058 &self.handle
1059 }
1060}
1061
1062#[cfg(test)]
1063mod tests {
1064 use super::*;
1065 use std::num::NonZeroU32;
1066 use std::ops::Deref;
1067 use std::sync::Arc;
1068 use std::task::Poll;
1069
1070 use assert_matches::assert_matches;
1071 use fuchsia_async::Fifo;
1072 use test_case::test_case;
1073 use zerocopy::{FromBytes, Immutable, IntoBytes};
1074
1075 use crate::session::DerivableConfig;
1076
1077 use super::buffer::{
1078 AllocKind, DescId, NETWORK_DEVICE_DESCRIPTOR_LENGTH, NETWORK_DEVICE_DESCRIPTOR_VERSION,
1079 };
1080 use super::{
1081 BufferLayout, BufferUsageEstimator, Config, DeviceBaseInfo, DeviceInfo, Error, Inner,
1082 Mutex, Pool, ReadyStorage, Task, TxIdleListeners, TxState,
1083 };
1084
1085 impl Inner {
1086 pub(super) fn new_test(
1087 pool: Arc<Pool>,
1088 proxy: netdev::SessionProxy,
1089 name: String,
1090 rx: Fifo<DescId<Rx>>,
1091 tx: Fifo<DescId<Tx>>,
1092 num_rx_buffers: usize,
1093 tx_ready: Mutex<ReadyStorage<DescId<Tx>>>,
1094 tx_idle_listeners: TxIdleListeners,
1095 tx_state: Mutex<TxState>,
1096 ) -> Self {
1097 Self {
1098 pool,
1099 proxy,
1100 name,
1101 rx,
1102 tx,
1103 num_rx_buffers,
1104 tx_ready,
1105 tx_idle_listeners,
1106 tx_state,
1107 }
1108 }
1109
1110 pub(super) fn tx_state(&self) -> &Mutex<TxState> {
1111 &self.tx_state
1112 }
1113
1114 pub(super) fn pool(&self) -> &Arc<Pool> {
1115 &self.pool
1116 }
1117 }
1118
1119 impl Task {
1120 pub(super) fn new_test(
1121 inner: Arc<Inner>,
1122 sample_interval: Option<std::time::Duration>,
1123 ) -> Self {
1124 let buffer_usage_sampler = sample_interval
1125 .map(|i| (fasync::Interval::new(i.into()), BufferUsageEstimator::new()));
1126 Self { inner, buffer_usage_sampler }
1127 }
1128 }
1129
1130 pub(super) const DEFAULT_DEVICE_BASE_INFO: DeviceBaseInfo = DeviceBaseInfo {
1131 rx_depth: 1,
1132 tx_depth: 1,
1133 buffer_alignment: 1,
1134 max_buffer_length: None,
1135 min_rx_buffer_length: 0,
1136 min_tx_buffer_head: 0,
1137 min_tx_buffer_length: 0,
1138 min_tx_buffer_tail: 0,
1139 max_buffer_parts: fidl_fuchsia_hardware_network::MAX_DESCRIPTOR_CHAIN,
1140 min_rx_buffers: None,
1141 };
1142
1143 pub(super) const DEFAULT_DEVICE_INFO: DeviceInfo = DeviceInfo {
1144 min_descriptor_length: 0,
1145 descriptor_version: 1,
1146 base_info: DEFAULT_DEVICE_BASE_INFO,
1147 };
1148
1149 const DEFAULT_BUFFER_LENGTH: usize = 2048;
1150
1151 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1152 min_descriptor_length: u8::MAX,
1153 ..DEFAULT_DEVICE_INFO
1154 }, format!("descriptor length too small: {} < {}", NETWORK_DEVICE_DESCRIPTOR_LENGTH, u8::MAX))]
1155 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1156 descriptor_version: 42,
1157 ..DEFAULT_DEVICE_INFO
1158 }, format!("descriptor version mismatch: {} != {}", NETWORK_DEVICE_DESCRIPTOR_VERSION, 42))]
1159 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1160 base_info: DeviceBaseInfo {
1161 tx_depth: 0,
1162 ..DEFAULT_DEVICE_BASE_INFO
1163 },
1164 ..DEFAULT_DEVICE_INFO
1165 }, "no TX buffers")]
1166 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1167 base_info: DeviceBaseInfo {
1168 rx_depth: 0,
1169 ..DEFAULT_DEVICE_BASE_INFO
1170 },
1171 ..DEFAULT_DEVICE_INFO
1172 }, "no RX buffers")]
1173 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1174 base_info: DeviceBaseInfo {
1175 tx_depth: u16::MAX,
1176 rx_depth: u16::MAX,
1177 ..DEFAULT_DEVICE_BASE_INFO
1178 },
1179 ..DEFAULT_DEVICE_INFO
1180 }, format!("too many buffers requested: {} + {} > u16::MAX", u16::MAX, u16::MAX))]
1181 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1182 base_info: DeviceBaseInfo {
1183 min_tx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1184 ..DEFAULT_DEVICE_BASE_INFO
1185 },
1186 ..DEFAULT_DEVICE_INFO
1187 }, format!(
1188 "buffer_length smaller than minimum TX requirement: {} < {}",
1189 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1190 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1191 base_info: DeviceBaseInfo {
1192 min_tx_buffer_head: DEFAULT_BUFFER_LENGTH as u16 + 1,
1193 ..DEFAULT_DEVICE_BASE_INFO
1194 },
1195 ..DEFAULT_DEVICE_INFO
1196 }, format!(
1197 "buffer length {} does not meet minimum tx buffer head/tail requirement {}/0",
1198 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1199 #[test_case(DEFAULT_BUFFER_LENGTH, DeviceInfo {
1200 base_info: DeviceBaseInfo {
1201 min_tx_buffer_tail: DEFAULT_BUFFER_LENGTH as u16 + 1,
1202 ..DEFAULT_DEVICE_BASE_INFO
1203 },
1204 ..DEFAULT_DEVICE_INFO
1205 }, format!(
1206 "buffer length {} does not meet minimum tx buffer head/tail requirement 0/{}",
1207 DEFAULT_BUFFER_LENGTH, DEFAULT_BUFFER_LENGTH + 1))]
1208 #[test_case(0, DEFAULT_DEVICE_INFO, "buffer_stride is zero")]
1209 #[test_case(usize::MAX, DEFAULT_DEVICE_INFO,
1210 format!(
1211 "too much memory required for the buffers: {} * {} > isize::MAX",
1212 usize::MAX, 2))]
1213 #[test_case(usize::MAX, DeviceInfo {
1214 base_info: DeviceBaseInfo {
1215 buffer_alignment: 2,
1216 ..DEFAULT_DEVICE_BASE_INFO
1217 },
1218 ..DEFAULT_DEVICE_INFO
1219 }, format!(
1220 "not possible to align {} to {} under usize::MAX",
1221 usize::MAX, 2))]
1222 fn configs_from_device_info_err(
1223 buffer_length: usize,
1224 info: DeviceInfo,
1225 expected: impl Deref<Target = str>,
1226 ) {
1227 let config = DerivableConfig { default_buffer_length: buffer_length, ..Default::default() };
1228 assert_matches!(
1229 info.make_config(config),
1230 Err(Error::Config(got)) if got.as_str() == expected.deref()
1231 );
1232 }
1233
1234 #[test_case(DeviceInfo {
1235 base_info: DeviceBaseInfo {
1236 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 + 1,
1237 ..DEFAULT_DEVICE_BASE_INFO
1238 },
1239 ..DEFAULT_DEVICE_INFO
1240 }, DEFAULT_BUFFER_LENGTH + 1; "default below min")]
1241 #[test_case(DeviceInfo {
1242 base_info: DeviceBaseInfo {
1243 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 - 1),
1244 ..DEFAULT_DEVICE_BASE_INFO
1245 },
1246 ..DEFAULT_DEVICE_INFO
1247 }, DEFAULT_BUFFER_LENGTH - 1; "default above max")]
1248 #[test_case(DeviceInfo {
1249 base_info: DeviceBaseInfo {
1250 min_rx_buffer_length: DEFAULT_BUFFER_LENGTH as u32 - 1,
1251 max_buffer_length: NonZeroU32::new(DEFAULT_BUFFER_LENGTH as u32 + 1),
1252 ..DEFAULT_DEVICE_BASE_INFO
1253 },
1254 ..DEFAULT_DEVICE_INFO
1255 }, DEFAULT_BUFFER_LENGTH; "default in bounds")]
1256 fn configs_from_device_buffer_length(info: DeviceInfo, expected_length: usize) {
1257 let config = info
1258 .make_config(DerivableConfig {
1259 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1260 ..Default::default()
1261 })
1262 .expect("is valid");
1263 let Config {
1264 buffer_layout: BufferLayout { length, min_tx_data: _, min_tx_head: _, min_tx_tail: _ },
1265 buffer_stride: _,
1266 rx_vmos: _,
1267 tx_vmos: _,
1268 options: _,
1269 buffer_usage_sample_interval: _,
1270 } = config;
1271 assert_eq!(length, expected_length);
1272 }
1273
1274 #[test]
1275 fn multi_vmo_allocation_scheme() {
1276 let info = DeviceInfo {
1277 base_info: DeviceBaseInfo { rx_depth: 16, tx_depth: 16, ..DEFAULT_DEVICE_BASE_INFO },
1278 ..DEFAULT_DEVICE_INFO
1279 };
1280 let config = info
1281 .make_config(DerivableConfig { multi_vmo: true, ..Default::default() })
1282 .expect("is valid");
1283 let Config { rx_vmos, tx_vmos, .. } = config;
1284 let expected_rx = vec![VmoConfig { vmo_id: 0, num_buffers: 16 }];
1285 let expected_tx = vec![
1286 VmoConfig { vmo_id: 1, num_buffers: 2 },
1287 VmoConfig { vmo_id: 2, num_buffers: 2 },
1288 VmoConfig { vmo_id: 3, num_buffers: 4 },
1289 VmoConfig { vmo_id: 4, num_buffers: 8 },
1290 ];
1291 assert_eq!(rx_vmos, expected_rx);
1292 assert_eq!(tx_vmos, expected_tx);
1293 }
1294
1295 #[test]
1296 fn multi_vmo_allocation_scheme_with_min_rx_buffers() {
1297 let info = DeviceInfo {
1298 base_info: DeviceBaseInfo {
1299 rx_depth: 16,
1300 tx_depth: 16,
1301 min_rx_buffers: NonZeroU16::new(2),
1302 ..DEFAULT_DEVICE_BASE_INFO
1303 },
1304 ..DEFAULT_DEVICE_INFO
1305 };
1306 let config = info
1307 .make_config(DerivableConfig { multi_vmo: true, ..Default::default() })
1308 .expect("is valid");
1309 let Config { rx_vmos, tx_vmos, .. } = config;
1310 let expected_rx = vec![
1311 VmoConfig { vmo_id: 0, num_buffers: 2 },
1312 VmoConfig { vmo_id: 1, num_buffers: 2 },
1313 VmoConfig { vmo_id: 2, num_buffers: 4 },
1314 VmoConfig { vmo_id: 3, num_buffers: 8 },
1315 ];
1316 let expected_tx = vec![
1317 VmoConfig { vmo_id: 4, num_buffers: 2 },
1318 VmoConfig { vmo_id: 5, num_buffers: 2 },
1319 VmoConfig { vmo_id: 6, num_buffers: 4 },
1320 VmoConfig { vmo_id: 7, num_buffers: 8 },
1321 ];
1322 assert_eq!(rx_vmos, expected_rx);
1323 assert_eq!(tx_vmos, expected_tx);
1324 }
1325
1326 pub(super) fn make_fifos<K: AllocKind>() -> (Fifo<DescId<K>>, zx::Fifo<DescId<K>>) {
1327 let (handle, other_end) = zx::Fifo::create(256).unwrap();
1328 (Fifo::from_fifo(handle), other_end)
1329 }
1330
1331 fn remove_rights<T: FromBytes + IntoBytes + Immutable>(
1332 fifo: Fifo<T>,
1333 rights_to_remove: zx::Rights,
1334 ) -> Fifo<T> {
1335 let fifo = zx::Fifo::from(fifo);
1336 let rights = fifo.as_handle_ref().basic_info().expect("can retrieve info").rights;
1337
1338 let fifo = fifo.replace_handle(rights ^ rights_to_remove).expect("can replace");
1339 Fifo::from_fifo(fifo)
1340 }
1341
1342 enum TxOrRx {
1343 Tx,
1344 Rx,
1345 }
1346 #[test_case(TxOrRx::Tx, zx::Rights::READ; "tx read")]
1347 #[test_case(TxOrRx::Tx, zx::Rights::WRITE; "tx write")]
1348 #[test_case(TxOrRx::Rx, zx::Rights::WRITE; "rx read")]
1349 #[fuchsia::test]
1350 async fn task_as_future_poll_error(which_fifo: TxOrRx, right_to_remove: zx::Rights) {
1351 let config = DEFAULT_DEVICE_INFO
1359 .make_config(DerivableConfig {
1360 default_buffer_length: DEFAULT_BUFFER_LENGTH,
1361 ..Default::default()
1362 })
1363 .expect("is valid");
1364 let CreatedPool { pool, descriptors_vmo: _descriptors_vmo, data_vmos: _data_vmos } =
1365 Pool::new(config).expect("is valid");
1366 let (session_proxy, _session_server) =
1367 fidl::endpoints::create_proxy::<fidl_fuchsia_hardware_network::SessionMarker>();
1368
1369 let (rx, _rx_sender) = make_fifos();
1370 let (tx, _tx_receiver) = make_fifos();
1371
1372 let (tx, rx) = match which_fifo {
1374 TxOrRx::Tx => (remove_rights(tx, right_to_remove), rx),
1375 TxOrRx::Rx => (tx, remove_rights(rx, right_to_remove)),
1376 };
1377
1378 let tx_state = Mutex::new(TxState::new(vec![]));
1379
1380 let buf = pool.alloc_tx_buffer(1).await.expect("can allocate");
1381 let inner = Arc::new(Inner {
1382 pool,
1383 proxy: session_proxy,
1384 name: "fake_task".to_string(),
1385 rx,
1386 tx,
1387 num_rx_buffers: 10,
1388 tx_ready: Mutex::new(ReadyStorage::new(10)),
1389 tx_idle_listeners: TxIdleListeners::new(),
1390 tx_state,
1391 });
1392
1393 inner.send(buf);
1394
1395 let task = Task { inner, buffer_usage_sampler: None };
1396 futures::pin_mut!(task);
1397
1398 assert_matches!(futures::poll!(task.as_mut()), Poll::Ready(Err(Error::Fifo(_, _, _))));
1401 }
1402
1403 #[test_case(1; "drain first")]
1404 #[test_case(2; "drain first two")]
1405 #[test_case(3; "drain all")]
1406 #[fuchsia::test]
1407 async fn ready_storage_batch_iterator(drain_first_n: usize) {
1408 let (handle, fifo_server) = zx::Fifo::<u32>::create(256).unwrap();
1409 let fifo_client = Fifo::from_fifo(handle);
1410 let items = vec![10u32, 20u32, 30u32];
1411 let written = fifo_server.write(&items[..]).expect("write to fifo");
1412 assert_eq!(written.get(), 3);
1413
1414 let mut ready_storage = ReadyStorage::<u32>::new(10);
1415
1416 poll_fn(|cx| ready_storage.poll_fifo(cx, &fifo_client)).await.expect("fetch from fifo");
1418
1419 let mut drain = ready_storage.drain();
1420 for i in 0..drain_first_n {
1421 assert_eq!(drain.next(), Some(items[i]));
1422 }
1423 if drain_first_n == items.len() {
1424 assert_eq!(drain.next(), None);
1425 }
1426 std::mem::drop(drain);
1429
1430 let fetch_fut = poll_fn(|cx| ready_storage.poll_fifo(cx, &fifo_client));
1433 futures::pin_mut!(fetch_fut);
1434 assert_matches!(futures::poll!(fetch_fut), Poll::Pending);
1435 }
1436}