1use super::{TransportAddr, TransportId};
4use std::mem;
5use std::sync::{
6 Arc, Mutex,
7 atomic::{AtomicUsize, Ordering::Relaxed},
8};
9use tokio::sync::mpsc::{
10 Sender, UnboundedReceiver, UnboundedSender,
11 error::{TryRecvError, TrySendError},
12};
13
14pub(crate) trait PacketFastIngressSink: std::fmt::Debug + Send + Sync {
15 fn try_ingest_batch(&self, packets: &mut Vec<ReceivedPacket>) -> usize;
16}
17
18#[derive(Clone, Debug)]
20pub struct ReceivedPacket {
21 pub transport_id: TransportId,
23 pub remote_addr: TransportAddr,
25 pub data: PacketBuffer,
27 pub timestamp_ms: u64,
29 #[doc(hidden)]
31 pub trace_enqueued_at: Option<crate::perf_profile::TraceStamp>,
32 #[doc(hidden)]
36 pub trace_rx_loop_owned_at: Option<crate::perf_profile::TraceStamp>,
37}
38
39impl ReceivedPacket {
40 pub fn with_timestamp(
42 transport_id: TransportId,
43 remote_addr: TransportAddr,
44 data: PacketBuffer,
45 timestamp_ms: u64,
46 ) -> Self {
47 Self::with_trace_timestamp(
48 transport_id,
49 remote_addr,
50 data,
51 timestamp_ms,
52 crate::perf_profile::stamp(),
53 )
54 }
55
56 pub(crate) fn with_trace_timestamp(
63 transport_id: TransportId,
64 remote_addr: TransportAddr,
65 data: PacketBuffer,
66 timestamp_ms: u64,
67 trace_enqueued_at: Option<crate::perf_profile::TraceStamp>,
68 ) -> Self {
69 Self {
70 transport_id,
71 remote_addr,
72 data,
73 timestamp_ms,
74 trace_enqueued_at,
75 trace_rx_loop_owned_at: None,
76 }
77 }
78
79 pub(crate) fn is_transport_priority(&self) -> bool {
80 is_transport_priority_packet(self.data.as_slice())
81 }
82}
83
84#[derive(Debug, Default)]
89pub struct PacketBuffer {
90 data: Vec<u8>,
91 start: usize,
92 pool: Option<PacketBufferPool>,
93}
94
95impl PacketBuffer {
96 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
97 fn pooled(data: Vec<u8>, pool: PacketBufferPool) -> Self {
98 Self {
99 data,
100 start: 0,
101 pool: Some(pool),
102 }
103 }
104
105 pub fn new(data: Vec<u8>) -> Self {
106 Self {
107 data,
108 start: 0,
109 pool: None,
110 }
111 }
112
113 pub fn as_slice(&self) -> &[u8] {
114 &self.data[self.start..]
115 }
116
117 pub fn as_mut_slice(&mut self) -> &mut [u8] {
118 &mut self.data[self.start..]
119 }
120
121 pub fn len(&self) -> usize {
122 self.data.len().saturating_sub(self.start)
123 }
124
125 pub fn is_empty(&self) -> bool {
126 self.len() == 0
127 }
128
129 pub fn into_vec(mut self) -> Vec<u8> {
130 self.pool = None;
131 if self.start > 0 {
132 self.data.drain(..self.start);
133 self.start = 0;
134 }
135 mem::take(&mut self.data)
136 }
137
138 pub(crate) fn trim_front(&mut self, len: usize) -> bool {
139 if len > self.len() {
140 return false;
141 }
142 self.start += len;
143 true
144 }
145
146 pub(crate) fn truncate(&mut self, len: usize) {
147 if len < self.len() {
148 self.data.truncate(self.start + len);
149 }
150 }
151
152 pub(crate) fn extend_from_slice(&mut self, bytes: &[u8]) {
153 self.data.extend_from_slice(bytes);
154 }
155
156 pub(crate) fn try_prepend_slices(&mut self, parts: &[&[u8]], reserve_tail: usize) -> bool {
157 let prefix_len = parts
158 .iter()
159 .fold(0usize, |total, part| total.saturating_add(part.len()));
160 if prefix_len == 0 {
161 return self.data.capacity().saturating_sub(self.data.len()) >= reserve_tail;
162 }
163
164 let len = self.data.len();
165 if self.start >= prefix_len && self.data.capacity().saturating_sub(len) >= reserve_tail {
166 let new_start = self.start - prefix_len;
167 let mut offset = new_start;
168 for part in parts {
169 self.data[offset..offset + part.len()].copy_from_slice(part);
170 offset += part.len();
171 }
172 self.start = new_start;
173 return true;
174 }
175
176 if self.data.capacity().saturating_sub(len) < prefix_len.saturating_add(reserve_tail) {
177 return false;
178 }
179
180 unsafe {
184 let ptr = self.data.as_mut_ptr();
185 std::ptr::copy(
186 ptr.add(self.start),
187 ptr.add(self.start + prefix_len),
188 self.len(),
189 );
190 let mut offset = self.start;
191 for part in parts {
192 std::ptr::copy_nonoverlapping(part.as_ptr(), ptr.add(offset), part.len());
193 offset += part.len();
194 }
195 self.data.set_len(len + prefix_len);
196 }
197 true
198 }
199
200 pub(crate) fn replace_visible_prefix(&mut self, remove_len: usize, prefix: &[u8]) -> bool {
201 if remove_len > self.len() {
202 return false;
203 }
204
205 let prefix_len = prefix.len();
206 let tail_len = self.len() - remove_len;
207 if prefix_len >= remove_len {
208 let grow = prefix_len - remove_len;
209 if grow > 0 && self.start >= grow {
210 let new_start = self.start - grow;
211 self.data[new_start..new_start + prefix_len].copy_from_slice(prefix);
212 self.start = new_start;
213 return true;
214 }
215
216 let len = self.data.len();
217 if grow > 0 {
218 self.data.reserve(grow);
219 unsafe {
220 let ptr = self.data.as_mut_ptr();
221 std::ptr::copy(
222 ptr.add(self.start + remove_len),
223 ptr.add(self.start + prefix_len),
224 tail_len,
225 );
226 self.data.set_len(len + grow);
227 }
228 }
229 self.data[self.start..self.start + prefix_len].copy_from_slice(prefix);
230 return true;
231 }
232
233 let shrink = remove_len - prefix_len;
234 if tail_len > 0 {
235 self.data.copy_within(
236 self.start + remove_len..self.start + remove_len + tail_len,
237 self.start + prefix_len,
238 );
239 }
240 self.data.truncate(self.data.len() - shrink);
241 self.data[self.start..self.start + prefix_len].copy_from_slice(prefix);
242 true
243 }
244
245 pub(crate) fn recycle_batch(packets: &mut [Self]) {
246 let Some(pool) = packets.first().and_then(|packet| packet.pool.clone()) else {
247 return;
248 };
249 if packets.iter().all(|packet| {
250 packet
251 .pool
252 .as_ref()
253 .is_some_and(|packet_pool| pool.shares_storage(packet_pool))
254 }) {
255 for packet in packets.iter_mut() {
256 packet.pool = None;
257 }
258 pool.put_batch(packets);
259 }
260 }
261}
262
263impl Clone for PacketBuffer {
264 fn clone(&self) -> Self {
265 Self {
266 data: self.as_slice().to_vec(),
267 start: 0,
268 pool: None,
269 }
270 }
271}
272
273impl AsRef<[u8]> for PacketBuffer {
274 fn as_ref(&self) -> &[u8] {
275 self.as_slice()
276 }
277}
278
279impl Drop for PacketBuffer {
280 fn drop(&mut self) {
281 if let Some(pool) = self.pool.take() {
282 pool.put(mem::take(&mut self.data));
283 }
284 }
285}
286
287impl PartialEq for PacketBuffer {
288 fn eq(&self, other: &Self) -> bool {
289 self.as_slice() == other.as_slice()
290 }
291}
292
293impl Eq for PacketBuffer {}
294
295const FMP_VERSION: u8 = crate::node::wire::FMP_VERSION;
301const FMP_PHASE_ESTABLISHED: u8 = crate::node::wire::PHASE_ESTABLISHED;
302const FMP_PHASE_MSG1: u8 = crate::node::wire::PHASE_MSG1;
303const FMP_PHASE_MSG2: u8 = crate::node::wire::PHASE_MSG2;
304const FMP_COMMON_PREFIX_SIZE: usize = crate::node::wire::COMMON_PREFIX_SIZE;
305const FMP_ESTABLISHED_HEADER_SIZE: usize = crate::node::wire::ESTABLISHED_HEADER_SIZE;
306const FMP_MSG1_WIRE_SIZE: usize = crate::node::wire::MSG1_WIRE_SIZE;
307const FMP_MSG2_WIRE_SIZE: usize = crate::node::wire::MSG2_WIRE_SIZE;
308const AEAD_TAG_SIZE: usize = crate::noise::TAG_SIZE;
309const FMP_HEARTBEAT_PLAINTEXT_SIZE: usize = 4 + 1;
310const FMP_MMP_SENDER_REPORT_PLAINTEXT_SIZE: usize = crate::mmp::SENDER_REPORT_WIRE_SIZE;
311const FMP_MMP_RECEIVER_REPORT_PLAINTEXT_SIZE: usize = crate::mmp::RECEIVER_REPORT_WIRE_SIZE;
312
313fn is_transport_priority_packet(data: &[u8]) -> bool {
314 if data.len() < FMP_COMMON_PREFIX_SIZE {
315 return false;
316 }
317
318 let version = data[0] >> 4;
319 let phase = data[0] & 0x0F;
320 if version != FMP_VERSION {
321 return false;
322 }
323
324 match phase {
325 FMP_PHASE_MSG1 => data.len() == FMP_MSG1_WIRE_SIZE,
326 FMP_PHASE_MSG2 => data.len() == FMP_MSG2_WIRE_SIZE,
327 FMP_PHASE_ESTABLISHED => is_fmp_established_priority_packet(data),
328 _ => false,
329 }
330}
331
332fn is_fmp_established_priority_packet(data: &[u8]) -> bool {
333 if data.len() < FMP_ESTABLISHED_HEADER_SIZE.saturating_add(AEAD_TAG_SIZE) {
334 return false;
335 }
336
337 let payload_len = usize::from(u16::from_le_bytes([data[2], data[3]]));
338 let expected_len = FMP_ESTABLISHED_HEADER_SIZE
339 .saturating_add(payload_len)
340 .saturating_add(AEAD_TAG_SIZE);
341 if data.len() != expected_len {
342 return false;
343 }
344
345 matches!(
346 payload_len,
347 FMP_HEARTBEAT_PLAINTEXT_SIZE
348 | FMP_MMP_SENDER_REPORT_PLAINTEXT_SIZE
349 | FMP_MMP_RECEIVER_REPORT_PLAINTEXT_SIZE
350 )
351}
352
353const PACKET_BATCH_POOL_LIMIT: usize = 256;
355const PACKET_BATCH_MAX_RETAINED_CAPACITY: usize = 256;
357const PACKET_BUFFER_POOL_LIMIT: usize = 4096;
359const PACKET_BUFFER_MAX_RETAINED_CAPACITY: usize = 16 * 1024;
361
362const TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER: usize = 16_384;
369
370#[derive(Clone, Debug)]
378pub struct PacketTx {
379 priority: UnboundedSender<PacketQueueItem>,
380 bulk: Sender<PacketQueueItem>,
381 fast_ingress: Option<Arc<dyn PacketFastIngressSink>>,
382 batch_pool: PacketBatchPool,
383 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
384 buffer_pool: PacketBufferPool,
385 priority_queued_packets: Arc<AtomicUsize>,
388 queued_packets: Arc<AtomicUsize>,
389 bulk_queued_packets: Arc<AtomicUsize>,
390 bulk_packet_capacity: usize,
391 track_backlog: bool,
392}
393
394pub struct PacketRx {
396 priority: UnboundedReceiver<PacketQueueItem>,
397 bulk: tokio::sync::mpsc::Receiver<PacketQueueItem>,
398 priority_queued_packets: Arc<AtomicUsize>,
399 queued_packets: Arc<AtomicUsize>,
400 bulk_queued_packets: Arc<AtomicUsize>,
401 track_backlog: bool,
402 pending_priority: Option<PendingPackets>,
403 pending_bulk: Option<PendingPackets>,
404 priority_closed: bool,
405 bulk_closed: bool,
406}
407
408#[derive(Clone, Debug)]
409struct PacketBatchPool {
410 inner: Arc<Mutex<Vec<Vec<ReceivedPacket>>>>,
411}
412
413#[derive(Clone, Debug)]
414struct PacketBufferPool {
415 inner: Arc<Mutex<Vec<Vec<u8>>>>,
416 available: Arc<AtomicUsize>,
417}
418
419#[derive(Debug)]
420pub(crate) struct PacketBatch {
421 packets: Vec<ReceivedPacket>,
422 pool: Option<PacketBatchPool>,
423}
424
425#[derive(Debug)]
426enum PacketQueueItem {
427 One(ReceivedPacket),
428 Batch(PacketBatch),
429}
430
431#[derive(Clone, Copy)]
432enum PacketLane {
433 Priority,
434 Bulk,
435}
436
437#[derive(Clone, Copy)]
438enum PacketQueueTx {
439 Priority,
440 Bulk,
441}
442
443enum PacketSendFailure {
444 Closed(PacketQueueItem),
445 DroppedBulk(usize),
446}
447
448struct PendingPackets {
449 batch: PacketBatch,
450 rx_loop_owned_at: Option<crate::perf_profile::TraceStamp>,
451}
452
453#[derive(Debug, PartialEq, Eq)]
454struct PacketQueueDequeueCounts {
455 total: usize,
456 priority: usize,
457 bulk: usize,
458}
459
460impl PacketQueueTx {
461 fn try_send(self, owner: &PacketTx, item: PacketQueueItem) -> Result<(), PacketSendFailure> {
462 match self {
463 PacketQueueTx::Priority => owner
464 .priority
465 .send(item)
466 .map_err(|error| PacketSendFailure::Closed(error.0)),
467 PacketQueueTx::Bulk => {
468 let packet_count = item.packet_count();
469 match owner.bulk.try_send(item) {
470 Ok(()) => Ok(()),
471 Err(TrySendError::Full(_item)) => {
472 Err(PacketSendFailure::DroppedBulk(packet_count))
473 }
474 Err(TrySendError::Closed(item)) => Err(PacketSendFailure::Closed(item)),
475 }
476 }
477 }
478 }
479}
480
481impl PacketQueueItem {
482 fn packet_count(&self) -> usize {
483 match self {
484 PacketQueueItem::One(_) => 1,
485 PacketQueueItem::Batch(packets) => packets.packets.len(),
486 }
487 }
488
489 fn dequeue_counts(&self, lane: PacketLane) -> PacketQueueDequeueCounts {
490 let total = self.packet_count();
491 match lane {
492 PacketLane::Priority => PacketQueueDequeueCounts {
493 total,
494 priority: total,
495 bulk: 0,
496 },
497 PacketLane::Bulk => PacketQueueDequeueCounts {
498 total,
499 priority: 0,
500 bulk: total,
501 },
502 }
503 }
504
505 fn queued_at(&self) -> Option<crate::perf_profile::TraceStamp> {
506 match self {
507 PacketQueueItem::One(packet) => packet.trace_enqueued_at,
508 PacketQueueItem::Batch(packets) => packets
509 .packets
510 .first()
511 .and_then(|packet| packet.trace_enqueued_at),
512 }
513 }
514
515 fn record_dequeue_wait(&self, lane: PacketLane) {
516 let queued_at = self.queued_at();
517 if queued_at.is_none() {
518 return;
519 }
520 let counts = self.dequeue_counts(lane);
521 crate::perf_profile::record_since_split_count(
522 crate::perf_profile::Stage::TransportChannelWait,
523 crate::perf_profile::Stage::TransportPriorityChannelWait,
524 crate::perf_profile::Stage::TransportBulkChannelWait,
525 queued_at,
526 counts.total as u64,
527 counts.priority as u64,
528 counts.bulk as u64,
529 );
530 }
531}
532
533impl PacketBatchPool {
534 fn new() -> Self {
535 Self {
536 inner: Arc::new(Mutex::new(Vec::new())),
537 }
538 }
539
540 fn take(&self, capacity: usize) -> PacketBatch {
541 let packets = {
542 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
543 guard.pop()
544 };
545 if let Some(mut packets) = packets {
546 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolReuse);
547 packets.clear();
548 if packets.capacity() >= capacity {
549 return PacketBatch::pooled(packets, self.clone());
550 }
551 packets.reserve(capacity.saturating_sub(packets.capacity()));
552 return PacketBatch::pooled(packets, self.clone());
553 }
554 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolFresh);
555 PacketBatch::pooled(Vec::with_capacity(capacity), self.clone())
556 }
557
558 fn put(&self, mut packets: Vec<ReceivedPacket>) {
559 packets.clear();
560 if packets.capacity() > PACKET_BATCH_MAX_RETAINED_CAPACITY {
561 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolDiscard);
562 return;
563 }
564 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
565 if guard.len() < PACKET_BATCH_POOL_LIMIT {
566 guard.push(packets);
567 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolReturn);
568 } else {
569 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolDiscard);
570 }
571 }
572}
573
574impl PacketBufferPool {
575 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
576 fn new() -> Self {
577 Self {
578 inner: Arc::new(Mutex::new(Vec::new())),
579 available: Arc::new(AtomicUsize::new(0)),
580 }
581 }
582
583 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
584 fn take(&self, capacity: usize) -> Vec<u8> {
585 if self.available.load(Relaxed) > 0 {
586 let buffer = {
587 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
588 guard.pop()
589 };
590 if let Some(mut buffer) = buffer {
591 self.available.fetch_sub(1, Relaxed);
592 crate::perf_profile::record_event(
593 crate::perf_profile::Event::PacketBufferPoolReuse,
594 );
595 prepare_recv_buffer(&mut buffer, capacity);
596 return buffer;
597 }
598 }
599
600 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolFresh);
601 fresh_recv_buffer(capacity)
602 }
603
604 fn put(&self, mut buffer: Vec<u8>) {
605 buffer.clear();
606 if buffer.capacity() > PACKET_BUFFER_MAX_RETAINED_CAPACITY {
607 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolDiscard);
608 return;
609 }
610
611 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
612 if guard.len() < PACKET_BUFFER_POOL_LIMIT {
613 guard.push(buffer);
614 self.available.fetch_add(1, Relaxed);
615 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolReturn);
616 } else {
617 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolDiscard);
618 }
619 }
620
621 fn shares_storage(&self, other: &Self) -> bool {
622 Arc::ptr_eq(&self.inner, &other.inner)
623 }
624
625 fn put_batch(&self, packets: &mut [PacketBuffer]) {
626 let mut returned = 0usize;
627 let mut discarded = 0usize;
628 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
629 let available_slots = PACKET_BUFFER_POOL_LIMIT.saturating_sub(guard.len());
630 for packet in packets {
631 packet.start = 0;
632 let mut buffer = mem::take(&mut packet.data);
633 buffer.clear();
634 if buffer.capacity() <= PACKET_BUFFER_MAX_RETAINED_CAPACITY
635 && returned < available_slots
636 {
637 guard.push(buffer);
638 returned += 1;
639 } else {
640 discarded += 1;
641 }
642 }
643 if returned > 0 {
644 self.available.fetch_add(returned, Relaxed);
645 }
646 drop(guard);
647 if returned > 0 {
648 crate::perf_profile::record_event_count(
649 crate::perf_profile::Event::PacketBufferPoolReturn,
650 returned as u64,
651 );
652 }
653 if discarded > 0 {
654 crate::perf_profile::record_event_count(
655 crate::perf_profile::Event::PacketBufferPoolDiscard,
656 discarded as u64,
657 );
658 }
659 }
660}
661
662#[cfg(target_os = "macos")]
663fn fresh_recv_buffer(size: usize) -> Vec<u8> {
664 vec![0u8; size]
665}
666
667#[cfg(all(any(test, target_os = "linux"), not(target_os = "macos")))]
668fn fresh_recv_buffer(size: usize) -> Vec<u8> {
669 Vec::with_capacity(size)
670}
671
672#[cfg(target_os = "macos")]
673fn prepare_recv_buffer(buffer: &mut Vec<u8>, size: usize) {
674 buffer.resize(size, 0);
675}
676
677#[cfg(all(any(test, target_os = "linux"), not(target_os = "macos")))]
678fn prepare_recv_buffer(buffer: &mut Vec<u8>, size: usize) {
679 buffer.clear();
680 if buffer.capacity() < size {
681 buffer.reserve(size.saturating_sub(buffer.capacity()));
682 }
683}
684
685impl PacketBatch {
686 fn pooled(packets: Vec<ReceivedPacket>, pool: PacketBatchPool) -> Self {
687 Self {
688 packets,
689 pool: Some(pool),
690 }
691 }
692
693 pub(crate) fn push(&mut self, packet: ReceivedPacket) {
694 self.packets.push(packet);
695 }
696
697 pub(crate) fn is_empty(&self) -> bool {
698 self.packets.is_empty()
699 }
700
701 pub(crate) fn as_slice(&self) -> &[ReceivedPacket] {
702 &self.packets
703 }
704}
705
706impl Drop for PacketBatch {
707 fn drop(&mut self) {
708 let Some(pool) = self.pool.take() else {
709 return;
710 };
711 pool.put(mem::take(&mut self.packets));
712 }
713}
714
715impl PendingPackets {
716 fn new(
717 mut batch: PacketBatch,
718 rx_loop_owned_at: Option<crate::perf_profile::TraceStamp>,
719 ) -> Self {
720 batch.packets.reverse();
721 Self {
722 batch,
723 rx_loop_owned_at,
724 }
725 }
726
727 fn next(&mut self) -> Option<ReceivedPacket> {
728 let mut packet = self.batch.packets.pop()?;
729 if let Some(rx_loop_owned_at) = self.rx_loop_owned_at {
730 packet.trace_rx_loop_owned_at = Some(rx_loop_owned_at);
731 }
732 Some(packet)
733 }
734}
735
736impl PacketTx {
737 pub(crate) fn set_fast_ingress_sink(&mut self, sink: Arc<dyn PacketFastIngressSink>) {
738 self.fast_ingress = Some(sink);
739 }
740
741 pub(crate) fn try_fast_ingress_packet_batch(&self, batch: &mut PacketBatch) -> usize {
742 let Some(sink) = &self.fast_ingress else {
743 return 0;
744 };
745 sink.try_ingest_batch(&mut batch.packets)
746 }
747
748 pub(crate) fn packet_batch(&self, capacity: usize) -> PacketBatch {
749 self.batch_pool.take(capacity)
750 }
751
752 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
753 pub(crate) fn recv_buffer(&self, capacity: usize) -> Vec<u8> {
754 self.buffer_pool.take(capacity)
755 }
756
757 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
758 pub(crate) fn packet_buffer(&self, data: Vec<u8>) -> PacketBuffer {
759 PacketBuffer::pooled(data, self.buffer_pool.clone())
760 }
761
762 pub fn send(
763 &self,
764 packet: ReceivedPacket,
765 ) -> Result<(), tokio::sync::mpsc::error::SendError<ReceivedPacket>> {
766 let tx = if packet.is_transport_priority() {
767 PacketQueueTx::Priority
768 } else {
769 PacketQueueTx::Bulk
770 };
771 self.send_item(tx, PacketQueueItem::One(packet))
772 .map_err(|item| match item {
773 PacketQueueItem::One(packet) => tokio::sync::mpsc::error::SendError(packet),
774 PacketQueueItem::Batch(_) => {
775 unreachable!("single packet send cannot fail with a batch item")
776 }
777 })
778 }
779
780 pub(crate) fn send_packet_batch(&self, mut batch: PacketBatch) -> Result<(), ()> {
781 if batch.is_empty() {
782 return Ok(());
783 }
784
785 let packet_count = batch.packets.len();
786 let priority_count = batch
787 .packets
788 .iter()
789 .filter(|packet| packet.is_transport_priority())
790 .count();
791 if priority_count == 0 || priority_count == packet_count {
792 let tx = if priority_count == 0 {
793 PacketQueueTx::Bulk
794 } else {
795 PacketQueueTx::Priority
796 };
797 return self.send_packet_items(tx, batch);
798 }
799
800 let mut priority_packets = self.packet_batch(priority_count);
801 let mut bulk_packets = self.packet_batch(packet_count - priority_count);
802 for packet in batch.packets.drain(..) {
803 if packet.is_transport_priority() {
804 priority_packets.push(packet);
805 } else {
806 bulk_packets.push(packet);
807 }
808 }
809
810 self.send_packet_items(PacketQueueTx::Priority, priority_packets)?;
811 self.send_packet_items(PacketQueueTx::Bulk, bulk_packets)?;
812 Ok(())
813 }
814
815 fn send_packet_items(&self, tx: PacketQueueTx, packets: PacketBatch) -> Result<(), ()> {
816 if matches!(tx, PacketQueueTx::Bulk) {
817 return self.send_bulk_packet_items(packets);
818 }
819
820 let item = match packets.packets.len() {
821 0 => return Ok(()),
822 _ => PacketQueueItem::Batch(packets),
823 };
824 self.send_item(tx, item).map_err(|_| ())
825 }
826
827 fn send_bulk_packet_items(&self, mut packets: PacketBatch) -> Result<(), ()> {
828 let packet_count = packets.packets.len();
829 if packet_count == 0 {
830 return Ok(());
831 }
832
833 let granted = self.try_reserve_bulk_packet_prefix(packet_count);
834 if granted == 0 {
835 crate::perf_profile::record_event_count(
836 crate::perf_profile::Event::TransportBulkDropped,
837 packet_count as u64,
838 );
839 return Ok(());
840 }
841
842 if granted < packet_count {
843 let dropped = packet_count - granted;
844 let _dropped_tail = packets.packets.split_off(granted);
845 crate::perf_profile::record_event_count(
846 crate::perf_profile::Event::TransportBulkDropped,
847 dropped as u64,
848 );
849 }
850
851 let item = match packets.packets.len() {
852 0 => return Ok(()),
853 _ => PacketQueueItem::Batch(packets),
854 };
855 self.send_reserved_item(PacketQueueTx::Bulk, item, Some(granted))
856 .map_err(|_| ())
857 }
858
859 fn send_item(&self, tx: PacketQueueTx, item: PacketQueueItem) -> Result<(), PacketQueueItem> {
860 let packet_count = item.packet_count();
861 let bulk_reserved = if matches!(tx, PacketQueueTx::Bulk) && packet_count > 0 {
862 if !self.try_reserve_bulk_packets(packet_count) {
863 crate::perf_profile::record_event_count(
864 crate::perf_profile::Event::TransportBulkDropped,
865 packet_count as u64,
866 );
867 return Ok(());
868 }
869 Some(packet_count)
870 } else {
871 None
872 };
873 self.send_reserved_item(tx, item, bulk_reserved)
874 }
875
876 fn send_reserved_item(
877 &self,
878 tx: PacketQueueTx,
879 item: PacketQueueItem,
880 bulk_reserved: Option<usize>,
881 ) -> Result<(), PacketQueueItem> {
882 let packet_count = item.packet_count();
883 debug_assert_eq!(
884 bulk_reserved,
885 matches!(tx, PacketQueueTx::Bulk)
886 .then_some(packet_count)
887 .filter(|count| *count > 0)
888 );
889 let priority_reserved = matches!(tx, PacketQueueTx::Priority)
890 .then_some(packet_count)
891 .filter(|count| *count > 0);
892 if let Some(count) = priority_reserved {
893 self.priority_queued_packets.fetch_add(count, Relaxed);
894 }
895
896 let tracked_count = if self.track_backlog {
897 Some(packet_count)
898 } else {
899 None
900 };
901 let previous = tracked_count.map(|count| self.queued_packets.fetch_add(count, Relaxed));
902 match tx.try_send(self, item) {
903 Ok(()) => {
904 if let (Some(count), Some(previous)) = (tracked_count, previous) {
905 let queued = previous.saturating_add(count);
906 if previous < TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER
907 && queued >= TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER
908 {
909 crate::perf_profile::record_event(
910 crate::perf_profile::Event::TransportChannelBacklogHigh,
911 );
912 }
913 }
914 Ok(())
915 }
916 Err(PacketSendFailure::Closed(item)) => {
917 if let Some(count) = tracked_count {
918 self.queued_packets.fetch_sub(count, Relaxed);
919 }
920 if let Some(count) = priority_reserved {
921 release_priority_packets(&self.priority_queued_packets, count);
922 }
923 if let Some(count) = bulk_reserved {
924 self.release_bulk_packets(count);
925 }
926 Err(item)
927 }
928 Err(PacketSendFailure::DroppedBulk(dropped_count)) => {
929 if let Some(count) = tracked_count {
930 self.queued_packets.fetch_sub(count, Relaxed);
931 }
932 if let Some(count) = priority_reserved {
933 release_priority_packets(&self.priority_queued_packets, count);
934 }
935 if let Some(count) = bulk_reserved {
936 self.release_bulk_packets(count);
937 }
938 crate::perf_profile::record_event_count(
939 crate::perf_profile::Event::TransportBulkDropped,
940 dropped_count as u64,
941 );
942 Ok(())
943 }
944 }
945 }
946
947 fn try_reserve_bulk_packets(&self, count: usize) -> bool {
948 self.bulk_queued_packets
949 .fetch_update(Relaxed, Relaxed, |current| {
950 current
951 .checked_add(count)
952 .filter(|next| *next <= self.bulk_packet_capacity)
953 })
954 .is_ok()
955 }
956
957 fn try_reserve_bulk_packet_prefix(&self, requested: usize) -> usize {
958 if requested == 0 {
959 return 0;
960 }
961
962 let mut current = self.bulk_queued_packets.load(Relaxed);
963 loop {
964 let available = self.bulk_packet_capacity.saturating_sub(current);
965 let granted = requested.min(available);
966 if granted == 0 {
967 return 0;
968 }
969 match self.bulk_queued_packets.compare_exchange_weak(
970 current,
971 current + granted,
972 Relaxed,
973 Relaxed,
974 ) {
975 Ok(_) => return granted,
976 Err(actual) => current = actual,
977 }
978 }
979 }
980
981 fn release_bulk_packets(&self, count: usize) {
982 release_reserved_bulk_packets(&self.bulk_queued_packets, count);
983 }
984}
985
986impl PacketRx {
987 pub(crate) fn priority_queued_packets(&self) -> usize {
988 self.priority_queued_packets.load(Relaxed)
989 }
990
991 pub(crate) fn priority_ready_packets(&self) -> usize {
992 self.pending_priority
993 .as_ref()
994 .map_or(0, |packets| packets.batch.packets.len())
995 .saturating_add(self.priority_queued_packets())
996 }
997
998 pub async fn recv(&mut self) -> Option<ReceivedPacket> {
999 loop {
1000 match self.try_recv() {
1001 Ok(packet) => return Some(packet),
1002 Err(TryRecvError::Disconnected) => return None,
1003 Err(TryRecvError::Empty) => {}
1004 }
1005
1006 tokio::select! {
1007 biased;
1008 item = self.priority.recv(), if !self.priority_closed => {
1009 match item {
1010 Some(item) => {
1011 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
1012 return Some(packet);
1013 }
1014 }
1015 None => self.priority_closed = true,
1016 }
1017 }
1018 item = self.bulk.recv(), if !self.bulk_closed => {
1019 match item {
1020 Some(item) => {
1021 if let Some(packet) = self.packet_from_item(item, PacketLane::Bulk) {
1022 return Some(packet);
1023 }
1024 }
1025 None => self.bulk_closed = true,
1026 }
1027 }
1028 }
1029 }
1030 }
1031
1032 pub fn try_recv(&mut self) -> Result<ReceivedPacket, TryRecvError> {
1033 if let Some(packet) = Self::take_pending(&mut self.pending_priority) {
1034 return Ok(packet);
1035 }
1036
1037 if self.should_probe_priority() {
1038 match self.priority.try_recv() {
1039 Ok(item) => {
1040 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
1041 return Ok(packet);
1042 }
1043 }
1044 Err(TryRecvError::Empty) => {}
1045 Err(TryRecvError::Disconnected) => {
1046 self.priority_closed = true;
1047 }
1048 }
1049 }
1050
1051 if let Some(packet) = Self::take_pending(&mut self.pending_bulk) {
1052 return Ok(packet);
1053 }
1054
1055 match self.bulk.try_recv() {
1056 Ok(item) => self
1057 .packet_from_item(item, PacketLane::Bulk)
1058 .ok_or(TryRecvError::Empty),
1059 Err(TryRecvError::Empty) => {
1060 if self.priority_closed && self.bulk_closed {
1061 Err(TryRecvError::Disconnected)
1062 } else {
1063 Err(TryRecvError::Empty)
1064 }
1065 }
1066 Err(TryRecvError::Disconnected) => {
1067 self.bulk_closed = true;
1068 if self.priority_closed {
1069 Err(TryRecvError::Disconnected)
1070 } else {
1071 Err(TryRecvError::Empty)
1072 }
1073 }
1074 }
1075 }
1076
1077 pub(crate) fn drain_ready<F>(&mut self, limit: usize, mut consume: F) -> usize
1078 where
1079 F: FnMut(ReceivedPacket) -> bool,
1080 {
1081 let mut drained = 0usize;
1082 while drained < limit {
1083 if !self.drain_pending_priority(limit, &mut drained, &mut consume) {
1084 break;
1085 }
1086 if drained >= limit {
1087 break;
1088 }
1089
1090 if self.should_probe_priority() {
1091 match self.priority.try_recv() {
1092 Ok(item) => {
1093 if !self.drain_item(
1094 item,
1095 PacketLane::Priority,
1096 limit,
1097 &mut drained,
1098 &mut consume,
1099 ) {
1100 break;
1101 }
1102 continue;
1103 }
1104 Err(TryRecvError::Empty) => {}
1105 Err(TryRecvError::Disconnected) => {
1106 self.priority_closed = true;
1107 }
1108 }
1109 }
1110 if drained >= limit {
1111 break;
1112 }
1113
1114 if !self.drain_pending_bulk(limit, &mut drained, &mut consume) {
1115 break;
1116 }
1117 if drained >= limit {
1118 break;
1119 }
1120
1121 match self.bulk.try_recv() {
1122 Ok(item) => {
1123 if !self.drain_item(item, PacketLane::Bulk, limit, &mut drained, &mut consume) {
1124 break;
1125 }
1126 }
1127 Err(TryRecvError::Empty) => break,
1128 Err(TryRecvError::Disconnected) => {
1129 self.bulk_closed = true;
1130 break;
1131 }
1132 }
1133 }
1134 drained
1135 }
1136
1137 fn packet_from_item(
1138 &mut self,
1139 item: PacketQueueItem,
1140 lane: PacketLane,
1141 ) -> Option<ReceivedPacket> {
1142 item.record_dequeue_wait(lane);
1143 let packet_count = item.packet_count();
1144 if self.track_backlog {
1145 self.queued_packets.fetch_sub(packet_count, Relaxed);
1146 }
1147 if matches!(lane, PacketLane::Priority) {
1148 release_priority_packets(&self.priority_queued_packets, packet_count);
1149 }
1150 if matches!(lane, PacketLane::Bulk) {
1151 release_reserved_bulk_packets(&self.bulk_queued_packets, packet_count);
1152 }
1153 let rx_loop_owned_at = crate::perf_profile::stamp();
1154 match item {
1155 PacketQueueItem::One(mut packet) => {
1156 packet.trace_rx_loop_owned_at = rx_loop_owned_at;
1157 Some(packet)
1158 }
1159 PacketQueueItem::Batch(packets) => {
1160 let mut pending = PendingPackets::new(packets, rx_loop_owned_at);
1161 let packet = pending.next()?;
1162 if !pending.batch.packets.is_empty() {
1163 match lane {
1164 PacketLane::Priority => self.pending_priority = Some(pending),
1165 PacketLane::Bulk => self.pending_bulk = Some(pending),
1166 }
1167 }
1168 Some(packet)
1169 }
1170 }
1171 }
1172
1173 fn drain_item<F>(
1174 &mut self,
1175 item: PacketQueueItem,
1176 lane: PacketLane,
1177 limit: usize,
1178 drained: &mut usize,
1179 consume: &mut F,
1180 ) -> bool
1181 where
1182 F: FnMut(ReceivedPacket) -> bool,
1183 {
1184 if let Some(packet) = self.packet_from_item(item, lane) {
1185 *drained += 1;
1186 if !consume(packet) {
1187 return false;
1188 }
1189 }
1190
1191 match lane {
1192 PacketLane::Priority => self.drain_pending_priority(limit, drained, consume),
1193 PacketLane::Bulk => self.drain_pending_bulk(limit, drained, consume),
1194 }
1195 }
1196
1197 fn drain_pending_priority<F>(
1198 &mut self,
1199 limit: usize,
1200 drained: &mut usize,
1201 consume: &mut F,
1202 ) -> bool
1203 where
1204 F: FnMut(ReceivedPacket) -> bool,
1205 {
1206 while *drained < limit {
1207 let Some(packet) = Self::take_pending(&mut self.pending_priority) else {
1208 return true;
1209 };
1210 *drained += 1;
1211 if !consume(packet) {
1212 return false;
1213 }
1214 }
1215 true
1216 }
1217
1218 fn drain_pending_bulk<F>(&mut self, limit: usize, drained: &mut usize, consume: &mut F) -> bool
1219 where
1220 F: FnMut(ReceivedPacket) -> bool,
1221 {
1222 while *drained < limit {
1223 if self.should_probe_priority() {
1224 return true;
1225 }
1226 let Some(packet) = Self::take_pending(&mut self.pending_bulk) else {
1227 return true;
1228 };
1229 *drained += 1;
1230 if !consume(packet) {
1231 return false;
1232 }
1233 }
1234 true
1235 }
1236
1237 fn should_probe_priority(&self) -> bool {
1238 !self.priority_closed
1239 && (self.priority_queued_packets.load(Relaxed) > 0 || self.bulk_closed)
1240 }
1241
1242 fn take_pending(pending: &mut Option<PendingPackets>) -> Option<ReceivedPacket> {
1243 let packets = pending.as_mut()?;
1244 let packet = packets.next();
1245 if packets.batch.packets.is_empty() {
1246 *pending = None;
1247 }
1248 packet
1249 }
1250}
1251
1252#[inline]
1253fn packet_channel_tracks_backlog() -> bool {
1254 cfg!(test) || crate::perf_profile::enabled()
1255}
1256
1257fn release_reserved_bulk_packets(counter: &AtomicUsize, count: usize) {
1258 if count == 0 {
1259 return;
1260 }
1261
1262 let previous = counter.fetch_sub(count, Relaxed);
1263 debug_assert!(
1264 previous >= count,
1265 "transport bulk queued packet accounting underflow"
1266 );
1267}
1268
1269fn release_priority_packets(counter: &AtomicUsize, count: usize) {
1270 if count == 0 {
1271 return;
1272 }
1273
1274 let previous = counter.fetch_sub(count, Relaxed);
1275 debug_assert!(
1276 previous >= count,
1277 "transport priority queued packet accounting underflow"
1278 );
1279}
1280
1281pub fn packet_channel(buffer: usize) -> (PacketTx, PacketRx) {
1287 let (priority_tx, priority_rx) = tokio::sync::mpsc::unbounded_channel();
1288 let (bulk_tx, bulk_rx) = tokio::sync::mpsc::channel(buffer.max(1));
1289 let priority_queued_packets = Arc::new(AtomicUsize::new(0));
1290 let queued_packets = Arc::new(AtomicUsize::new(0));
1291 let bulk_queued_packets = Arc::new(AtomicUsize::new(0));
1292 let track_backlog = packet_channel_tracks_backlog();
1293 (
1294 PacketTx {
1295 priority: priority_tx,
1296 bulk: bulk_tx,
1297 fast_ingress: None,
1298 batch_pool: PacketBatchPool::new(),
1299 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
1300 buffer_pool: PacketBufferPool::new(),
1301 priority_queued_packets: Arc::clone(&priority_queued_packets),
1302 queued_packets: Arc::clone(&queued_packets),
1303 bulk_queued_packets: Arc::clone(&bulk_queued_packets),
1304 bulk_packet_capacity: buffer.max(1),
1305 track_backlog,
1306 },
1307 PacketRx {
1308 priority: priority_rx,
1309 bulk: bulk_rx,
1310 priority_queued_packets,
1311 queued_packets,
1312 bulk_queued_packets,
1313 track_backlog,
1314 pending_priority: None,
1315 pending_bulk: None,
1316 priority_closed: false,
1317 bulk_closed: false,
1318 },
1319 )
1320}
1321
1322#[cfg(test)]
1323mod tests;