From 8312400913119a1a6b66bd25dcd36f58e36c63d9 Mon Sep 17 00:00:00 2001 From: fanyang Date: Sun, 28 Jun 2026 23:26:34 +0800 Subject: [PATCH] perf(packet_def): replace split_off with advance (zero-copy) from #2381 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- easytier/src/instance/virtual_nic.rs | 7 ++++--- easytier/src/tunnel/packet_def.rs | 14 +++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/easytier/src/instance/virtual_nic.rs b/easytier/src/instance/virtual_nic.rs index 1faa1fd5..73673cf3 100644 --- a/easytier/src/instance/virtual_nic.rs +++ b/easytier/src/instance/virtual_nic.rs @@ -24,7 +24,7 @@ use crate::{ }; use byteorder::WriteBytesExt as _; -use bytes::{BufMut, BytesMut}; +use bytes::{Buf, BufMut, BytesMut}; use cidr::{Ipv4Inet, Ipv6Inet}; use futures::{SinkExt, Stream, StreamExt, lock::BiLock, ready}; use pin_project_lite::pin_project; @@ -180,12 +180,13 @@ impl ZCPacketToBytes for TunZCPacketToBytes { assert!(payload_offset >= 4); 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..]); self.fill_packet_info(&mut inner[0..4], proto)?; inner } else { - inner.split_off(payload_offset) + inner.advance(payload_offset); + inner }; tracing::debug!(?ret, ?payload_offset, "convert zc packet to tun packet"); diff --git a/easytier/src/tunnel/packet_def.rs b/easytier/src/tunnel/packet_def.rs index edb2fe96..c496a6f7 100644 --- a/easytier/src/tunnel/packet_def.rs +++ b/easytier/src/tunnel/packet_def.rs @@ -1,9 +1,10 @@ +use bytes::Buf; use bytes::Bytes; use bytes::BytesMut; +use zerocopy::byteorder::*; use zerocopy::AsBytes; use zerocopy::FromBytes; use zerocopy::FromZeroes; -use zerocopy::byteorder::*; type DefaultEndian = LittleEndian; @@ -638,7 +639,8 @@ impl ZCPacket { } 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> { @@ -703,11 +705,12 @@ impl ZCPacket { } pub fn tunnel_payload_bytes(mut self) -> BytesMut { - self.inner.split_off( + self.inner.advance( self.packet_type .get_packet_offsets() .peer_manager_header_offset, - ) + ); + self.inner } 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); } - 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 {