perf(packet_def): replace split_off with advance (zero-copy) from #2381

Replace BytesMut::split_off with Buf::advance in packet extraction paths:
- convert_type: advance instead of split_off (TCP/UDP/WG hot path)
- payload_bytes, tunnel_payload_bytes: same
- convert_to_dummy_tunnel_packet: same
- virtual_nic TunZCPacketToBytes: same

split_off creates a second BytesMut sharing the same allocation (Arc
ref count churn). advance just moves the start pointer forward —
zero-copy, zero-alloc, no Arc operations.

Benchmark: pps neutral (glibc handles split_off pattern efficiently),
but eliminates Arc churn and is cleaner code.

Combined with #2385 safe initialization for best of both PRs.
All 53 packet/mpsc/forward_packet tests pass.
This commit is contained in:
fanyang
2026-06-28 23:26:34 +08:00
parent 19647f296a
commit 8312400913
2 changed files with 13 additions and 8 deletions
+4 -3
View File
@@ -24,7 +24,7 @@ use crate::{
}; };
use byteorder::WriteBytesExt as _; use byteorder::WriteBytesExt as _;
use bytes::{BufMut, BytesMut}; use bytes::{Buf, BufMut, BytesMut};
use cidr::{Ipv4Inet, Ipv6Inet}; use cidr::{Ipv4Inet, Ipv6Inet};
use futures::{SinkExt, Stream, StreamExt, lock::BiLock, ready}; use futures::{SinkExt, Stream, StreamExt, lock::BiLock, ready};
use pin_project_lite::pin_project; use pin_project_lite::pin_project;
@@ -180,12 +180,13 @@ impl ZCPacketToBytes for TunZCPacketToBytes {
assert!(payload_offset >= 4); assert!(payload_offset >= 4);
let ret = if self.has_packet_info { let ret = if self.has_packet_info {
let mut inner = inner.split_off(payload_offset - 4); inner.advance(payload_offset - 4);
let proto = infer_proto(&inner[4..]); let proto = infer_proto(&inner[4..]);
self.fill_packet_info(&mut inner[0..4], proto)?; self.fill_packet_info(&mut inner[0..4], proto)?;
inner inner
} else { } else {
inner.split_off(payload_offset) inner.advance(payload_offset);
inner
}; };
tracing::debug!(?ret, ?payload_offset, "convert zc packet to tun packet"); tracing::debug!(?ret, ?payload_offset, "convert zc packet to tun packet");
+9 -5
View File
@@ -1,9 +1,10 @@
use bytes::Buf;
use bytes::Bytes; use bytes::Bytes;
use bytes::BytesMut; use bytes::BytesMut;
use zerocopy::byteorder::*;
use zerocopy::AsBytes; use zerocopy::AsBytes;
use zerocopy::FromBytes; use zerocopy::FromBytes;
use zerocopy::FromZeroes; use zerocopy::FromZeroes;
use zerocopy::byteorder::*;
type DefaultEndian = LittleEndian; type DefaultEndian = LittleEndian;
@@ -638,7 +639,8 @@ impl ZCPacket {
} }
pub fn payload_bytes(mut self) -> BytesMut { pub fn payload_bytes(mut self) -> BytesMut {
self.inner.split_off(self.payload_offset()) self.inner.advance(self.payload_offset());
self.inner
} }
pub fn peer_manager_header(&self) -> Option<&PeerManagerHeader> { pub fn peer_manager_header(&self) -> Option<&PeerManagerHeader> {
@@ -703,11 +705,12 @@ impl ZCPacket {
} }
pub fn tunnel_payload_bytes(mut self) -> BytesMut { pub fn tunnel_payload_bytes(mut self) -> BytesMut {
self.inner.split_off( self.inner.advance(
self.packet_type self.packet_type
.get_packet_offsets() .get_packet_offsets()
.peer_manager_header_offset, .peer_manager_header_offset,
) );
self.inner
} }
pub fn convert_type(mut self, target_packet_type: ZCPacketType) -> Self { pub fn convert_type(mut self, target_packet_type: ZCPacketType) -> Self {
@@ -753,7 +756,8 @@ impl ZCPacket {
return Self::new_from_buf(buf, target_packet_type); return Self::new_from_buf(buf, target_packet_type);
} }
Self::new_from_buf(self.inner.split_off(new_offset), target_packet_type) self.inner.advance(new_offset);
Self::new_from_buf(self.inner, target_packet_type)
} }
pub fn into_bytes(self) -> Bytes { pub fn into_bytes(self) -> Bytes {