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
246impl Clone for PacketBuffer {
247 fn clone(&self) -> Self {
248 Self {
249 data: self.as_slice().to_vec(),
250 start: 0,
251 pool: None,
252 }
253 }
254}
255
256impl AsRef<[u8]> for PacketBuffer {
257 fn as_ref(&self) -> &[u8] {
258 self.as_slice()
259 }
260}
261
262impl Drop for PacketBuffer {
263 fn drop(&mut self) {
264 if let Some(pool) = self.pool.take() {
265 pool.put(mem::take(&mut self.data));
266 }
267 }
268}
269
270impl PartialEq for PacketBuffer {
271 fn eq(&self, other: &Self) -> bool {
272 self.as_slice() == other.as_slice()
273 }
274}
275
276impl Eq for PacketBuffer {}
277
278const FMP_VERSION: u8 = crate::node::wire::FMP_VERSION;
284const FMP_PHASE_ESTABLISHED: u8 = crate::node::wire::PHASE_ESTABLISHED;
285const FMP_PHASE_MSG1: u8 = crate::node::wire::PHASE_MSG1;
286const FMP_PHASE_MSG2: u8 = crate::node::wire::PHASE_MSG2;
287const FMP_COMMON_PREFIX_SIZE: usize = crate::node::wire::COMMON_PREFIX_SIZE;
288const FMP_ESTABLISHED_HEADER_SIZE: usize = crate::node::wire::ESTABLISHED_HEADER_SIZE;
289const FMP_MSG1_WIRE_SIZE: usize = crate::node::wire::MSG1_WIRE_SIZE;
290const FMP_MSG2_WIRE_SIZE: usize = crate::node::wire::MSG2_WIRE_SIZE;
291const AEAD_TAG_SIZE: usize = crate::noise::TAG_SIZE;
292const FMP_HEARTBEAT_PLAINTEXT_SIZE: usize = 4 + 1;
293const FMP_MMP_SENDER_REPORT_PLAINTEXT_SIZE: usize = crate::mmp::SENDER_REPORT_WIRE_SIZE;
294const FMP_MMP_RECEIVER_REPORT_PLAINTEXT_SIZE: usize = crate::mmp::RECEIVER_REPORT_WIRE_SIZE;
295
296fn is_transport_priority_packet(data: &[u8]) -> bool {
297 if data.len() < FMP_COMMON_PREFIX_SIZE {
298 return false;
299 }
300
301 let version = data[0] >> 4;
302 let phase = data[0] & 0x0F;
303 if version != FMP_VERSION {
304 return false;
305 }
306
307 match phase {
308 FMP_PHASE_MSG1 => data.len() == FMP_MSG1_WIRE_SIZE,
309 FMP_PHASE_MSG2 => data.len() == FMP_MSG2_WIRE_SIZE,
310 FMP_PHASE_ESTABLISHED => is_fmp_established_priority_packet(data),
311 _ => false,
312 }
313}
314
315fn is_fmp_established_priority_packet(data: &[u8]) -> bool {
316 if data.len() < FMP_ESTABLISHED_HEADER_SIZE.saturating_add(AEAD_TAG_SIZE) {
317 return false;
318 }
319
320 let payload_len = usize::from(u16::from_le_bytes([data[2], data[3]]));
321 let expected_len = FMP_ESTABLISHED_HEADER_SIZE
322 .saturating_add(payload_len)
323 .saturating_add(AEAD_TAG_SIZE);
324 if data.len() != expected_len {
325 return false;
326 }
327
328 matches!(
329 payload_len,
330 FMP_HEARTBEAT_PLAINTEXT_SIZE
331 | FMP_MMP_SENDER_REPORT_PLAINTEXT_SIZE
332 | FMP_MMP_RECEIVER_REPORT_PLAINTEXT_SIZE
333 )
334}
335
336const PACKET_BATCH_POOL_LIMIT: usize = 256;
338const PACKET_BATCH_MAX_RETAINED_CAPACITY: usize = 256;
340const PACKET_BUFFER_POOL_LIMIT: usize = 4096;
342const PACKET_BUFFER_MAX_RETAINED_CAPACITY: usize = 16 * 1024;
344
345const TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER: usize = 16_384;
352
353#[derive(Clone, Debug)]
361pub struct PacketTx {
362 priority: UnboundedSender<PacketQueueItem>,
363 bulk: Sender<PacketQueueItem>,
364 fast_ingress: Option<Arc<dyn PacketFastIngressSink>>,
365 batch_pool: PacketBatchPool,
366 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
367 buffer_pool: PacketBufferPool,
368 priority_queued_packets: Arc<AtomicUsize>,
371 queued_packets: Arc<AtomicUsize>,
372 bulk_queued_packets: Arc<AtomicUsize>,
373 bulk_packet_capacity: usize,
374 track_backlog: bool,
375}
376
377pub struct PacketRx {
379 priority: UnboundedReceiver<PacketQueueItem>,
380 bulk: tokio::sync::mpsc::Receiver<PacketQueueItem>,
381 priority_queued_packets: Arc<AtomicUsize>,
382 queued_packets: Arc<AtomicUsize>,
383 bulk_queued_packets: Arc<AtomicUsize>,
384 track_backlog: bool,
385 pending_priority: Option<PendingPackets>,
386 pending_bulk: Option<PendingPackets>,
387 priority_closed: bool,
388 bulk_closed: bool,
389}
390
391#[derive(Clone, Debug)]
392struct PacketBatchPool {
393 inner: Arc<Mutex<Vec<Vec<ReceivedPacket>>>>,
394}
395
396#[derive(Clone, Debug)]
397struct PacketBufferPool {
398 inner: Arc<Mutex<Vec<Vec<u8>>>>,
399 available: Arc<AtomicUsize>,
400}
401
402#[derive(Debug)]
403pub(crate) struct PacketBatch {
404 packets: Vec<ReceivedPacket>,
405 pool: Option<PacketBatchPool>,
406}
407
408#[derive(Debug)]
409enum PacketQueueItem {
410 One(ReceivedPacket),
411 Batch(PacketBatch),
412}
413
414#[derive(Clone, Copy)]
415enum PacketLane {
416 Priority,
417 Bulk,
418}
419
420#[derive(Clone, Copy)]
421enum PacketQueueTx {
422 Priority,
423 Bulk,
424}
425
426enum PacketSendFailure {
427 Closed(PacketQueueItem),
428 DroppedBulk(usize),
429}
430
431struct PendingPackets {
432 batch: PacketBatch,
433 rx_loop_owned_at: Option<crate::perf_profile::TraceStamp>,
434}
435
436#[derive(Debug, PartialEq, Eq)]
437struct PacketQueueDequeueCounts {
438 total: usize,
439 priority: usize,
440 bulk: usize,
441}
442
443impl PacketQueueTx {
444 fn try_send(self, owner: &PacketTx, item: PacketQueueItem) -> Result<(), PacketSendFailure> {
445 match self {
446 PacketQueueTx::Priority => owner
447 .priority
448 .send(item)
449 .map_err(|error| PacketSendFailure::Closed(error.0)),
450 PacketQueueTx::Bulk => {
451 let packet_count = item.packet_count();
452 match owner.bulk.try_send(item) {
453 Ok(()) => Ok(()),
454 Err(TrySendError::Full(_item)) => {
455 Err(PacketSendFailure::DroppedBulk(packet_count))
456 }
457 Err(TrySendError::Closed(item)) => Err(PacketSendFailure::Closed(item)),
458 }
459 }
460 }
461 }
462}
463
464impl PacketQueueItem {
465 fn packet_count(&self) -> usize {
466 match self {
467 PacketQueueItem::One(_) => 1,
468 PacketQueueItem::Batch(packets) => packets.packets.len(),
469 }
470 }
471
472 fn dequeue_counts(&self, lane: PacketLane) -> PacketQueueDequeueCounts {
473 let total = self.packet_count();
474 match lane {
475 PacketLane::Priority => PacketQueueDequeueCounts {
476 total,
477 priority: total,
478 bulk: 0,
479 },
480 PacketLane::Bulk => PacketQueueDequeueCounts {
481 total,
482 priority: 0,
483 bulk: total,
484 },
485 }
486 }
487
488 fn queued_at(&self) -> Option<crate::perf_profile::TraceStamp> {
489 match self {
490 PacketQueueItem::One(packet) => packet.trace_enqueued_at,
491 PacketQueueItem::Batch(packets) => packets
492 .packets
493 .first()
494 .and_then(|packet| packet.trace_enqueued_at),
495 }
496 }
497
498 fn record_dequeue_wait(&self, lane: PacketLane) {
499 let queued_at = self.queued_at();
500 if queued_at.is_none() {
501 return;
502 }
503 let counts = self.dequeue_counts(lane);
504 crate::perf_profile::record_since_split_count(
505 crate::perf_profile::Stage::TransportChannelWait,
506 crate::perf_profile::Stage::TransportPriorityChannelWait,
507 crate::perf_profile::Stage::TransportBulkChannelWait,
508 queued_at,
509 counts.total as u64,
510 counts.priority as u64,
511 counts.bulk as u64,
512 );
513 }
514}
515
516impl PacketBatchPool {
517 fn new() -> Self {
518 Self {
519 inner: Arc::new(Mutex::new(Vec::new())),
520 }
521 }
522
523 fn take(&self, capacity: usize) -> PacketBatch {
524 let packets = {
525 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
526 guard.pop()
527 };
528 if let Some(mut packets) = packets {
529 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolReuse);
530 packets.clear();
531 if packets.capacity() >= capacity {
532 return PacketBatch::pooled(packets, self.clone());
533 }
534 packets.reserve(capacity.saturating_sub(packets.capacity()));
535 return PacketBatch::pooled(packets, self.clone());
536 }
537 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolFresh);
538 PacketBatch::pooled(Vec::with_capacity(capacity), self.clone())
539 }
540
541 fn put(&self, mut packets: Vec<ReceivedPacket>) {
542 packets.clear();
543 if packets.capacity() > PACKET_BATCH_MAX_RETAINED_CAPACITY {
544 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolDiscard);
545 return;
546 }
547 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
548 if guard.len() < PACKET_BATCH_POOL_LIMIT {
549 guard.push(packets);
550 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolReturn);
551 } else {
552 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBatchPoolDiscard);
553 }
554 }
555}
556
557impl PacketBufferPool {
558 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
559 fn new() -> Self {
560 Self {
561 inner: Arc::new(Mutex::new(Vec::new())),
562 available: Arc::new(AtomicUsize::new(0)),
563 }
564 }
565
566 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
567 fn take(&self, capacity: usize) -> Vec<u8> {
568 if self.available.load(Relaxed) > 0 {
569 let buffer = {
570 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
571 guard.pop()
572 };
573 if let Some(mut buffer) = buffer {
574 self.available.fetch_sub(1, Relaxed);
575 crate::perf_profile::record_event(
576 crate::perf_profile::Event::PacketBufferPoolReuse,
577 );
578 prepare_recv_buffer(&mut buffer, capacity);
579 return buffer;
580 }
581 }
582
583 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolFresh);
584 fresh_recv_buffer(capacity)
585 }
586
587 fn put(&self, mut buffer: Vec<u8>) {
588 buffer.clear();
589 if buffer.capacity() > PACKET_BUFFER_MAX_RETAINED_CAPACITY {
590 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolDiscard);
591 return;
592 }
593
594 let mut guard = self.inner.lock().unwrap_or_else(|error| error.into_inner());
595 if guard.len() < PACKET_BUFFER_POOL_LIMIT {
596 guard.push(buffer);
597 self.available.fetch_add(1, Relaxed);
598 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolReturn);
599 } else {
600 crate::perf_profile::record_event(crate::perf_profile::Event::PacketBufferPoolDiscard);
601 }
602 }
603}
604
605#[cfg(target_os = "macos")]
606fn fresh_recv_buffer(size: usize) -> Vec<u8> {
607 vec![0u8; size]
608}
609
610#[cfg(all(any(test, target_os = "linux"), not(target_os = "macos")))]
611fn fresh_recv_buffer(size: usize) -> Vec<u8> {
612 Vec::with_capacity(size)
613}
614
615#[cfg(target_os = "macos")]
616fn prepare_recv_buffer(buffer: &mut Vec<u8>, size: usize) {
617 buffer.resize(size, 0);
618}
619
620#[cfg(all(any(test, target_os = "linux"), not(target_os = "macos")))]
621fn prepare_recv_buffer(buffer: &mut Vec<u8>, size: usize) {
622 buffer.clear();
623 if buffer.capacity() < size {
624 buffer.reserve(size.saturating_sub(buffer.capacity()));
625 }
626}
627
628impl PacketBatch {
629 fn pooled(packets: Vec<ReceivedPacket>, pool: PacketBatchPool) -> Self {
630 Self {
631 packets,
632 pool: Some(pool),
633 }
634 }
635
636 pub(crate) fn push(&mut self, packet: ReceivedPacket) {
637 self.packets.push(packet);
638 }
639
640 pub(crate) fn is_empty(&self) -> bool {
641 self.packets.is_empty()
642 }
643}
644
645impl Drop for PacketBatch {
646 fn drop(&mut self) {
647 let Some(pool) = self.pool.take() else {
648 return;
649 };
650 pool.put(mem::take(&mut self.packets));
651 }
652}
653
654impl PendingPackets {
655 fn new(
656 mut batch: PacketBatch,
657 rx_loop_owned_at: Option<crate::perf_profile::TraceStamp>,
658 ) -> Self {
659 batch.packets.reverse();
660 Self {
661 batch,
662 rx_loop_owned_at,
663 }
664 }
665
666 fn next(&mut self) -> Option<ReceivedPacket> {
667 let mut packet = self.batch.packets.pop()?;
668 if let Some(rx_loop_owned_at) = self.rx_loop_owned_at {
669 packet.trace_rx_loop_owned_at = Some(rx_loop_owned_at);
670 }
671 Some(packet)
672 }
673}
674
675impl PacketTx {
676 pub(crate) fn set_fast_ingress_sink(&mut self, sink: Arc<dyn PacketFastIngressSink>) {
677 self.fast_ingress = Some(sink);
678 }
679
680 pub(crate) fn try_fast_ingress_packet_batch(&self, batch: &mut PacketBatch) -> usize {
681 let Some(sink) = &self.fast_ingress else {
682 return 0;
683 };
684 sink.try_ingest_batch(&mut batch.packets)
685 }
686
687 pub(crate) fn packet_batch(&self, capacity: usize) -> PacketBatch {
688 self.batch_pool.take(capacity)
689 }
690
691 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
692 pub(crate) fn recv_buffer(&self, capacity: usize) -> Vec<u8> {
693 self.buffer_pool.take(capacity)
694 }
695
696 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
697 pub(crate) fn packet_buffer(&self, data: Vec<u8>) -> PacketBuffer {
698 PacketBuffer::pooled(data, self.buffer_pool.clone())
699 }
700
701 pub fn send(
702 &self,
703 packet: ReceivedPacket,
704 ) -> Result<(), tokio::sync::mpsc::error::SendError<ReceivedPacket>> {
705 let tx = if packet.is_transport_priority() {
706 PacketQueueTx::Priority
707 } else {
708 PacketQueueTx::Bulk
709 };
710 self.send_item(tx, PacketQueueItem::One(packet))
711 .map_err(|item| match item {
712 PacketQueueItem::One(packet) => tokio::sync::mpsc::error::SendError(packet),
713 PacketQueueItem::Batch(_) => {
714 unreachable!("single packet send cannot fail with a batch item")
715 }
716 })
717 }
718
719 pub(crate) fn send_packet_batch(&self, mut batch: PacketBatch) -> Result<(), ()> {
720 if batch.is_empty() {
721 return Ok(());
722 }
723
724 let packet_count = batch.packets.len();
725 let priority_count = batch
726 .packets
727 .iter()
728 .filter(|packet| packet.is_transport_priority())
729 .count();
730 if priority_count == 0 || priority_count == packet_count {
731 let tx = if priority_count == 0 {
732 PacketQueueTx::Bulk
733 } else {
734 PacketQueueTx::Priority
735 };
736 return self.send_packet_items(tx, batch);
737 }
738
739 let mut priority_packets = self.packet_batch(priority_count);
740 let mut bulk_packets = self.packet_batch(packet_count - priority_count);
741 for packet in batch.packets.drain(..) {
742 if packet.is_transport_priority() {
743 priority_packets.push(packet);
744 } else {
745 bulk_packets.push(packet);
746 }
747 }
748
749 self.send_packet_items(PacketQueueTx::Priority, priority_packets)?;
750 self.send_packet_items(PacketQueueTx::Bulk, bulk_packets)?;
751 Ok(())
752 }
753
754 fn send_packet_items(&self, tx: PacketQueueTx, packets: PacketBatch) -> Result<(), ()> {
755 if matches!(tx, PacketQueueTx::Bulk) {
756 return self.send_bulk_packet_items(packets);
757 }
758
759 let item = match packets.packets.len() {
760 0 => return Ok(()),
761 _ => PacketQueueItem::Batch(packets),
762 };
763 self.send_item(tx, item).map_err(|_| ())
764 }
765
766 fn send_bulk_packet_items(&self, mut packets: PacketBatch) -> Result<(), ()> {
767 let packet_count = packets.packets.len();
768 if packet_count == 0 {
769 return Ok(());
770 }
771
772 let granted = self.try_reserve_bulk_packet_prefix(packet_count);
773 if granted == 0 {
774 crate::perf_profile::record_event_count(
775 crate::perf_profile::Event::TransportBulkDropped,
776 packet_count as u64,
777 );
778 return Ok(());
779 }
780
781 if granted < packet_count {
782 let dropped = packet_count - granted;
783 let _dropped_tail = packets.packets.split_off(granted);
784 crate::perf_profile::record_event_count(
785 crate::perf_profile::Event::TransportBulkDropped,
786 dropped as u64,
787 );
788 }
789
790 let item = match packets.packets.len() {
791 0 => return Ok(()),
792 _ => PacketQueueItem::Batch(packets),
793 };
794 self.send_reserved_item(PacketQueueTx::Bulk, item, Some(granted))
795 .map_err(|_| ())
796 }
797
798 fn send_item(&self, tx: PacketQueueTx, item: PacketQueueItem) -> Result<(), PacketQueueItem> {
799 let packet_count = item.packet_count();
800 let bulk_reserved = if matches!(tx, PacketQueueTx::Bulk) && packet_count > 0 {
801 if !self.try_reserve_bulk_packets(packet_count) {
802 crate::perf_profile::record_event_count(
803 crate::perf_profile::Event::TransportBulkDropped,
804 packet_count as u64,
805 );
806 return Ok(());
807 }
808 Some(packet_count)
809 } else {
810 None
811 };
812 self.send_reserved_item(tx, item, bulk_reserved)
813 }
814
815 fn send_reserved_item(
816 &self,
817 tx: PacketQueueTx,
818 item: PacketQueueItem,
819 bulk_reserved: Option<usize>,
820 ) -> Result<(), PacketQueueItem> {
821 let packet_count = item.packet_count();
822 debug_assert_eq!(
823 bulk_reserved,
824 matches!(tx, PacketQueueTx::Bulk)
825 .then_some(packet_count)
826 .filter(|count| *count > 0)
827 );
828 let priority_reserved = matches!(tx, PacketQueueTx::Priority)
829 .then_some(packet_count)
830 .filter(|count| *count > 0);
831 if let Some(count) = priority_reserved {
832 self.priority_queued_packets.fetch_add(count, Relaxed);
833 }
834
835 let tracked_count = if self.track_backlog {
836 Some(packet_count)
837 } else {
838 None
839 };
840 let previous = tracked_count.map(|count| self.queued_packets.fetch_add(count, Relaxed));
841 match tx.try_send(self, item) {
842 Ok(()) => {
843 if let (Some(count), Some(previous)) = (tracked_count, previous) {
844 let queued = previous.saturating_add(count);
845 if previous < TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER
846 && queued >= TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER
847 {
848 crate::perf_profile::record_event(
849 crate::perf_profile::Event::TransportChannelBacklogHigh,
850 );
851 }
852 }
853 Ok(())
854 }
855 Err(PacketSendFailure::Closed(item)) => {
856 if let Some(count) = tracked_count {
857 self.queued_packets.fetch_sub(count, Relaxed);
858 }
859 if let Some(count) = priority_reserved {
860 release_priority_packets(&self.priority_queued_packets, count);
861 }
862 if let Some(count) = bulk_reserved {
863 self.release_bulk_packets(count);
864 }
865 Err(item)
866 }
867 Err(PacketSendFailure::DroppedBulk(dropped_count)) => {
868 if let Some(count) = tracked_count {
869 self.queued_packets.fetch_sub(count, Relaxed);
870 }
871 if let Some(count) = priority_reserved {
872 release_priority_packets(&self.priority_queued_packets, count);
873 }
874 if let Some(count) = bulk_reserved {
875 self.release_bulk_packets(count);
876 }
877 crate::perf_profile::record_event_count(
878 crate::perf_profile::Event::TransportBulkDropped,
879 dropped_count as u64,
880 );
881 Ok(())
882 }
883 }
884 }
885
886 fn try_reserve_bulk_packets(&self, count: usize) -> bool {
887 self.bulk_queued_packets
888 .fetch_update(Relaxed, Relaxed, |current| {
889 current
890 .checked_add(count)
891 .filter(|next| *next <= self.bulk_packet_capacity)
892 })
893 .is_ok()
894 }
895
896 fn try_reserve_bulk_packet_prefix(&self, requested: usize) -> usize {
897 if requested == 0 {
898 return 0;
899 }
900
901 let mut current = self.bulk_queued_packets.load(Relaxed);
902 loop {
903 let available = self.bulk_packet_capacity.saturating_sub(current);
904 let granted = requested.min(available);
905 if granted == 0 {
906 return 0;
907 }
908 match self.bulk_queued_packets.compare_exchange_weak(
909 current,
910 current + granted,
911 Relaxed,
912 Relaxed,
913 ) {
914 Ok(_) => return granted,
915 Err(actual) => current = actual,
916 }
917 }
918 }
919
920 fn release_bulk_packets(&self, count: usize) {
921 release_reserved_bulk_packets(&self.bulk_queued_packets, count);
922 }
923}
924
925impl PacketRx {
926 pub(crate) fn priority_queued_packets(&self) -> usize {
927 self.priority_queued_packets.load(Relaxed)
928 }
929
930 pub(crate) fn priority_ready_packets(&self) -> usize {
931 self.pending_priority
932 .as_ref()
933 .map_or(0, |packets| packets.batch.packets.len())
934 .saturating_add(self.priority_queued_packets())
935 }
936
937 pub async fn recv(&mut self) -> Option<ReceivedPacket> {
938 loop {
939 match self.try_recv() {
940 Ok(packet) => return Some(packet),
941 Err(TryRecvError::Disconnected) => return None,
942 Err(TryRecvError::Empty) => {}
943 }
944
945 tokio::select! {
946 biased;
947 item = self.priority.recv(), if !self.priority_closed => {
948 match item {
949 Some(item) => {
950 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
951 return Some(packet);
952 }
953 }
954 None => self.priority_closed = true,
955 }
956 }
957 item = self.bulk.recv(), if !self.bulk_closed => {
958 match item {
959 Some(item) => {
960 if let Some(packet) = self.packet_from_item(item, PacketLane::Bulk) {
961 return Some(packet);
962 }
963 }
964 None => self.bulk_closed = true,
965 }
966 }
967 }
968 }
969 }
970
971 pub fn try_recv(&mut self) -> Result<ReceivedPacket, TryRecvError> {
972 if let Some(packet) = Self::take_pending(&mut self.pending_priority) {
973 return Ok(packet);
974 }
975
976 if self.should_probe_priority() {
977 match self.priority.try_recv() {
978 Ok(item) => {
979 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
980 return Ok(packet);
981 }
982 }
983 Err(TryRecvError::Empty) => {}
984 Err(TryRecvError::Disconnected) => {
985 self.priority_closed = true;
986 }
987 }
988 }
989
990 if let Some(packet) = Self::take_pending(&mut self.pending_bulk) {
991 return Ok(packet);
992 }
993
994 match self.bulk.try_recv() {
995 Ok(item) => self
996 .packet_from_item(item, PacketLane::Bulk)
997 .ok_or(TryRecvError::Empty),
998 Err(TryRecvError::Empty) => {
999 if self.priority_closed && self.bulk_closed {
1000 Err(TryRecvError::Disconnected)
1001 } else {
1002 Err(TryRecvError::Empty)
1003 }
1004 }
1005 Err(TryRecvError::Disconnected) => {
1006 self.bulk_closed = true;
1007 if self.priority_closed {
1008 Err(TryRecvError::Disconnected)
1009 } else {
1010 Err(TryRecvError::Empty)
1011 }
1012 }
1013 }
1014 }
1015
1016 pub(crate) fn drain_ready<F>(&mut self, limit: usize, mut consume: F) -> usize
1017 where
1018 F: FnMut(ReceivedPacket) -> bool,
1019 {
1020 let mut drained = 0usize;
1021 while drained < limit {
1022 if !self.drain_pending_priority(limit, &mut drained, &mut consume) {
1023 break;
1024 }
1025 if drained >= limit {
1026 break;
1027 }
1028
1029 if self.should_probe_priority() {
1030 match self.priority.try_recv() {
1031 Ok(item) => {
1032 if !self.drain_item(
1033 item,
1034 PacketLane::Priority,
1035 limit,
1036 &mut drained,
1037 &mut consume,
1038 ) {
1039 break;
1040 }
1041 continue;
1042 }
1043 Err(TryRecvError::Empty) => {}
1044 Err(TryRecvError::Disconnected) => {
1045 self.priority_closed = true;
1046 }
1047 }
1048 }
1049 if drained >= limit {
1050 break;
1051 }
1052
1053 if !self.drain_pending_bulk(limit, &mut drained, &mut consume) {
1054 break;
1055 }
1056 if drained >= limit {
1057 break;
1058 }
1059
1060 match self.bulk.try_recv() {
1061 Ok(item) => {
1062 if !self.drain_item(item, PacketLane::Bulk, limit, &mut drained, &mut consume) {
1063 break;
1064 }
1065 }
1066 Err(TryRecvError::Empty) => break,
1067 Err(TryRecvError::Disconnected) => {
1068 self.bulk_closed = true;
1069 break;
1070 }
1071 }
1072 }
1073 drained
1074 }
1075
1076 fn packet_from_item(
1077 &mut self,
1078 item: PacketQueueItem,
1079 lane: PacketLane,
1080 ) -> Option<ReceivedPacket> {
1081 item.record_dequeue_wait(lane);
1082 let packet_count = item.packet_count();
1083 if self.track_backlog {
1084 self.queued_packets.fetch_sub(packet_count, Relaxed);
1085 }
1086 if matches!(lane, PacketLane::Priority) {
1087 release_priority_packets(&self.priority_queued_packets, packet_count);
1088 }
1089 if matches!(lane, PacketLane::Bulk) {
1090 release_reserved_bulk_packets(&self.bulk_queued_packets, packet_count);
1091 }
1092 let rx_loop_owned_at = crate::perf_profile::stamp();
1093 match item {
1094 PacketQueueItem::One(mut packet) => {
1095 packet.trace_rx_loop_owned_at = rx_loop_owned_at;
1096 Some(packet)
1097 }
1098 PacketQueueItem::Batch(packets) => {
1099 let mut pending = PendingPackets::new(packets, rx_loop_owned_at);
1100 let packet = pending.next()?;
1101 if !pending.batch.packets.is_empty() {
1102 match lane {
1103 PacketLane::Priority => self.pending_priority = Some(pending),
1104 PacketLane::Bulk => self.pending_bulk = Some(pending),
1105 }
1106 }
1107 Some(packet)
1108 }
1109 }
1110 }
1111
1112 fn drain_item<F>(
1113 &mut self,
1114 item: PacketQueueItem,
1115 lane: PacketLane,
1116 limit: usize,
1117 drained: &mut usize,
1118 consume: &mut F,
1119 ) -> bool
1120 where
1121 F: FnMut(ReceivedPacket) -> bool,
1122 {
1123 if let Some(packet) = self.packet_from_item(item, lane) {
1124 *drained += 1;
1125 if !consume(packet) {
1126 return false;
1127 }
1128 }
1129
1130 match lane {
1131 PacketLane::Priority => self.drain_pending_priority(limit, drained, consume),
1132 PacketLane::Bulk => self.drain_pending_bulk(limit, drained, consume),
1133 }
1134 }
1135
1136 fn drain_pending_priority<F>(
1137 &mut self,
1138 limit: usize,
1139 drained: &mut usize,
1140 consume: &mut F,
1141 ) -> bool
1142 where
1143 F: FnMut(ReceivedPacket) -> bool,
1144 {
1145 while *drained < limit {
1146 let Some(packet) = Self::take_pending(&mut self.pending_priority) else {
1147 return true;
1148 };
1149 *drained += 1;
1150 if !consume(packet) {
1151 return false;
1152 }
1153 }
1154 true
1155 }
1156
1157 fn drain_pending_bulk<F>(&mut self, limit: usize, drained: &mut usize, consume: &mut F) -> bool
1158 where
1159 F: FnMut(ReceivedPacket) -> bool,
1160 {
1161 while *drained < limit {
1162 if self.should_probe_priority() {
1163 return true;
1164 }
1165 let Some(packet) = Self::take_pending(&mut self.pending_bulk) else {
1166 return true;
1167 };
1168 *drained += 1;
1169 if !consume(packet) {
1170 return false;
1171 }
1172 }
1173 true
1174 }
1175
1176 fn should_probe_priority(&self) -> bool {
1177 !self.priority_closed
1178 && (self.priority_queued_packets.load(Relaxed) > 0 || self.bulk_closed)
1179 }
1180
1181 fn take_pending(pending: &mut Option<PendingPackets>) -> Option<ReceivedPacket> {
1182 let packets = pending.as_mut()?;
1183 let packet = packets.next();
1184 if packets.batch.packets.is_empty() {
1185 *pending = None;
1186 }
1187 packet
1188 }
1189}
1190
1191#[inline]
1192fn packet_channel_tracks_backlog() -> bool {
1193 cfg!(test) || crate::perf_profile::enabled()
1194}
1195
1196fn release_reserved_bulk_packets(counter: &AtomicUsize, count: usize) {
1197 if count == 0 {
1198 return;
1199 }
1200
1201 let previous = counter.fetch_sub(count, Relaxed);
1202 debug_assert!(
1203 previous >= count,
1204 "transport bulk queued packet accounting underflow"
1205 );
1206}
1207
1208fn release_priority_packets(counter: &AtomicUsize, count: usize) {
1209 if count == 0 {
1210 return;
1211 }
1212
1213 let previous = counter.fetch_sub(count, Relaxed);
1214 debug_assert!(
1215 previous >= count,
1216 "transport priority queued packet accounting underflow"
1217 );
1218}
1219
1220pub fn packet_channel(buffer: usize) -> (PacketTx, PacketRx) {
1226 let (priority_tx, priority_rx) = tokio::sync::mpsc::unbounded_channel();
1227 let (bulk_tx, bulk_rx) = tokio::sync::mpsc::channel(buffer.max(1));
1228 let priority_queued_packets = Arc::new(AtomicUsize::new(0));
1229 let queued_packets = Arc::new(AtomicUsize::new(0));
1230 let bulk_queued_packets = Arc::new(AtomicUsize::new(0));
1231 let track_backlog = packet_channel_tracks_backlog();
1232 (
1233 PacketTx {
1234 priority: priority_tx,
1235 bulk: bulk_tx,
1236 fast_ingress: None,
1237 batch_pool: PacketBatchPool::new(),
1238 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
1239 buffer_pool: PacketBufferPool::new(),
1240 priority_queued_packets: Arc::clone(&priority_queued_packets),
1241 queued_packets: Arc::clone(&queued_packets),
1242 bulk_queued_packets: Arc::clone(&bulk_queued_packets),
1243 bulk_packet_capacity: buffer.max(1),
1244 track_backlog,
1245 },
1246 PacketRx {
1247 priority: priority_rx,
1248 bulk: bulk_rx,
1249 priority_queued_packets,
1250 queued_packets,
1251 bulk_queued_packets,
1252 track_backlog,
1253 pending_priority: None,
1254 pending_bulk: None,
1255 priority_closed: false,
1256 bulk_closed: false,
1257 },
1258 )
1259}
1260
1261#[cfg(test)]
1262mod tests;