perf(packet_def): apply #2385 ZCPacket safe initialization

Cherry-pick packet_def.rs changes from PR #2385:
- new_with_payload: write_bytes + copy_nonoverlapping (no aliasing check)
- new_for_tun: resize instead of unsafe set_len
- new_for_foreign_network: stack-allocated header + single write
- convert_type: resize instead of set_len

Eliminates UB from set_len on uninitialized memory. copy_nonoverlapping
skips aliasing checks, slightly faster for TCP path.

Benchmark (10s, 1400B):
  TCP:  440K -> 464K pps (+5.5%)
  Ring: 508K -> 473K pps (-7%, header zeroing overhead)

Ring regression is acceptable: ring is only for in-process benchmark,
real deployments use TCP/UDP over WAN where the TCP gain matters.

All 37 packet + 16 forward_packet tests pass.
This commit is contained in:
fanyang
2026-06-28 23:07:33 +08:00
parent 94d056cb78
commit 19647f296a
+72 -19
View File
@@ -483,8 +483,16 @@ impl ZCPacket {
let payload_off = ret.packet_type.get_packet_offsets().payload_offset; let payload_off = ret.packet_type.get_packet_offsets().payload_offset;
let total_len = payload_off + payload.len(); let total_len = payload_off + payload.len();
ret.inner.reserve(total_len); ret.inner.reserve(total_len);
unsafe { ret.inner.set_len(total_len) };
ret.mut_payload()[..payload.len()].copy_from_slice(payload); // SAFETY: `reserve` guarantees capacity >= total_len.
// We zero the header region and copy payload before advancing length,
// so every byte in [0..total_len) is initialized before any read.
unsafe {
let ptr = ret.inner.as_mut_ptr();
std::ptr::write_bytes(ptr, 0, payload_off);
std::ptr::copy_nonoverlapping(payload.as_ptr(), ptr.add(payload_off), payload.len());
ret.inner.set_len(total_len);
}
ret ret
} }
@@ -492,12 +500,12 @@ impl ZCPacket {
let mut ret = Self::new_nic_packet(); let mut ret = Self::new_nic_packet();
ret.inner.reserve(cap); ret.inner.reserve(cap);
let total_len = ret.packet_type.get_packet_offsets().payload_offset - packet_info_len; let total_len = ret.packet_type.get_packet_offsets().payload_offset - packet_info_len;
unsafe { ret.inner.set_len(total_len) }; ret.inner.resize(total_len, 0);
ret ret
} }
pub fn new_for_foreign_network( pub fn new_for_foreign_network(
network_name: &String, network_name: &str,
dst_peer_id: u32, dst_peer_id: u32,
foreign_zc_packet: &ZCPacket, foreign_zc_packet: &ZCPacket,
) -> Self { ) -> Self {
@@ -506,26 +514,71 @@ impl ZCPacket {
foreign_network_hdr.get_header_len() + foreign_zc_packet.tunnel_payload().len(); foreign_network_hdr.get_header_len() + foreign_zc_packet.tunnel_payload().len();
let mut ret = Self::new_nic_packet(); let mut ret = Self::new_nic_packet();
let payload_off = ret.packet_type.get_packet_offsets().payload_offset; let offsets = ret.packet_type.get_packet_offsets();
ret.inner.reserve(payload_off + total_payload_len); let payload_off = offsets.payload_offset;
unsafe { ret.inner.set_len(payload_off + total_payload_len) }; let pm_hdr_off = offsets.peer_manager_header_offset;
let total_len = payload_off + total_payload_len;
ret.inner.reserve(total_len);
let fixed_hdr_len = std::mem::size_of::<ForeignNetworkPacketHeader>(); let fixed_hdr_len = std::mem::size_of::<ForeignNetworkPacketHeader>();
ret.mut_payload()[..fixed_hdr_len].copy_from_slice(foreign_network_hdr.as_bytes());
let name_offset = foreign_network_hdr.network_name_offset.get() as usize; let name_offset = foreign_network_hdr.network_name_offset.get() as usize;
let name_len = foreign_network_hdr.network_name_len.get() as usize; let name_len = foreign_network_hdr.network_name_len.get() as usize;
ret.mut_payload()[name_offset..name_offset + name_len] let foreign_payload = foreign_zc_packet.tunnel_payload();
.copy_from_slice(network_name.as_bytes());
ret.mut_payload()[foreign_network_hdr.get_header_len()..] // Construct the PeerManagerHeader on the stack so we can write it
.copy_from_slice(foreign_zc_packet.tunnel_payload()); // directly into the buffer, avoiding a separate mut_peer_manager_header()
// call after set_len.
let pm_hdr = PeerManagerHeader {
from_peer_id: 0.into(),
to_peer_id: 0.into(),
packet_type: PacketType::ForeignNetworkPacket as u8,
flags: 0,
forward_counter: 0,
reserved: 0,
len: U32::new(total_payload_len as u32),
};
let hdr = ret.mut_peer_manager_header().unwrap(); // SAFETY: `reserve` guarantees capacity >= total_len.
hdr.from_peer_id = 0.into(); // We zero only the tunnel-header reserved space [0..pm_hdr_off], write
hdr.to_peer_id = 0.into(); // the PeerManagerHeader directly at pm_hdr_off, then copy the foreign
hdr.packet_type = PacketType::ForeignNetworkPacket as u8; // network header, network name, and payload. Every byte in [0..total_len)
hdr.len.set(total_payload_len as u32); // is initialized before set_len.
unsafe {
let ptr = ret.inner.as_mut_ptr();
// Zero the tunnel header reserved space only (not the PM header region)
std::ptr::write_bytes(ptr, 0, pm_hdr_off);
// Write PeerManagerHeader directly
std::ptr::copy_nonoverlapping(
pm_hdr.as_bytes().as_ptr(),
ptr.add(pm_hdr_off),
std::mem::size_of::<PeerManagerHeader>(),
);
// Copy foreign network fixed header
std::ptr::copy_nonoverlapping(
foreign_network_hdr.as_bytes().as_ptr(),
ptr.add(payload_off),
fixed_hdr_len,
);
// Copy network name
std::ptr::copy_nonoverlapping(
network_name.as_ptr(),
ptr.add(payload_off + name_offset),
name_len,
);
// Copy foreign payload
std::ptr::copy_nonoverlapping(
foreign_payload.as_ptr(),
ptr.add(payload_off + foreign_network_hdr.get_header_len()),
foreign_payload.len(),
);
ret.inner.set_len(total_len);
}
ret ret
} }
@@ -695,7 +748,7 @@ impl ZCPacket {
.get_packet_offsets() .get_packet_offsets()
.peer_manager_header_offset; .peer_manager_header_offset;
let mut buf = BytesMut::with_capacity(new_pm_offset + tunnel_payload.len()); let mut buf = BytesMut::with_capacity(new_pm_offset + tunnel_payload.len());
unsafe { buf.set_len(new_pm_offset) }; buf.resize(new_pm_offset, 0);
buf.extend_from_slice(tunnel_payload); buf.extend_from_slice(tunnel_payload);
return Self::new_from_buf(buf, target_packet_type); return Self::new_from_buf(buf, target_packet_type);
} }