Skip to content

Commit 19f7e29

Browse files
AlexanderYastrebovjwhited
authored andcommitted
device: reduce RoutineHandshake allocations
Reduce allocations by eliminating byte reader, hand-rolled decoding and reusing message structs. Synthetic benchmark: var msgSink MessageInitiation func BenchmarkMessageInitiationUnmarshal(b *testing.B) { packet := make([]byte, MessageInitiationSize) reader := bytes.NewReader(packet) err := binary.Read(reader, binary.LittleEndian, &msgSink) if err != nil { b.Fatal(err) } b.Run("binary.Read", func(b *testing.B) { b.ReportAllocs() for range b.N { reader := bytes.NewReader(packet) _ = binary.Read(reader, binary.LittleEndian, &msgSink) } }) b.Run("unmarshal", func(b *testing.B) { b.ReportAllocs() for range b.N { _ = msgSink.unmarshal(packet) } }) } Results: │ - │ │ sec/op │ MessageInitiationUnmarshal/binary.Read-8 1.508µ ± 2% MessageInitiationUnmarshal/unmarshal-8 12.66n ± 2% │ - │ │ B/op │ MessageInitiationUnmarshal/binary.Read-8 208.0 ± 0% MessageInitiationUnmarshal/unmarshal-8 0.000 ± 0% │ - │ │ allocs/op │ MessageInitiationUnmarshal/binary.Read-8 2.000 ± 0% MessageInitiationUnmarshal/unmarshal-8 0.000 ± 0% cherry picked from commit WireGuard/wireguard-go@9e7529c Updates tailscale/corp#28879 Signed-off-by: Alexander Yastrebov <[email protected]> Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent f74ff38 commit 19f7e29

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

device/noise-protocol.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package device
77

88
import (
9+
"encoding/binary"
910
"errors"
1011
"fmt"
1112
"sync"
@@ -115,6 +116,53 @@ type MessageCookieReply struct {
115116
Cookie [blake2s.Size128 + poly1305.TagSize]byte
116117
}
117118

119+
var errMessageTooShort = errors.New("message too short")
120+
121+
func (msg *MessageInitiation) unmarshal(b []byte) error {
122+
if len(b) < MessageInitiationSize {
123+
return errMessageTooShort
124+
}
125+
126+
msg.Type = binary.LittleEndian.Uint32(b)
127+
msg.Sender = binary.LittleEndian.Uint32(b[4:])
128+
copy(msg.Ephemeral[:], b[8:])
129+
copy(msg.Static[:], b[8+len(msg.Ephemeral):])
130+
copy(msg.Timestamp[:], b[8+len(msg.Ephemeral)+len(msg.Static):])
131+
copy(msg.MAC1[:], b[8+len(msg.Ephemeral)+len(msg.Static)+len(msg.Timestamp):])
132+
copy(msg.MAC2[:], b[8+len(msg.Ephemeral)+len(msg.Static)+len(msg.Timestamp)+len(msg.MAC1):])
133+
134+
return nil
135+
}
136+
137+
func (msg *MessageResponse) unmarshal(b []byte) error {
138+
if len(b) < MessageResponseSize {
139+
return errMessageTooShort
140+
}
141+
142+
msg.Type = binary.LittleEndian.Uint32(b)
143+
msg.Sender = binary.LittleEndian.Uint32(b[4:])
144+
msg.Receiver = binary.LittleEndian.Uint32(b[8:])
145+
copy(msg.Ephemeral[:], b[12:])
146+
copy(msg.Empty[:], b[12+len(msg.Ephemeral):])
147+
copy(msg.MAC1[:], b[12+len(msg.Ephemeral)+len(msg.Empty):])
148+
copy(msg.MAC2[:], b[12+len(msg.Ephemeral)+len(msg.Empty)+len(msg.MAC1):])
149+
150+
return nil
151+
}
152+
153+
func (msg *MessageCookieReply) unmarshal(b []byte) error {
154+
if len(b) < MessageCookieReplySize {
155+
return errMessageTooShort
156+
}
157+
158+
msg.Type = binary.LittleEndian.Uint32(b)
159+
msg.Receiver = binary.LittleEndian.Uint32(b[4:])
160+
copy(msg.Nonce[:], b[8:])
161+
copy(msg.Cookie[:], b[8+len(msg.Nonce):])
162+
163+
return nil
164+
}
165+
118166
type Handshake struct {
119167
state handshakeState
120168
mutex sync.RWMutex

device/receive.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package device
77

88
import (
9-
"bytes"
109
"encoding/binary"
1110
"errors"
1211
"net"
@@ -287,8 +286,7 @@ func (device *Device) RoutineHandshake(id int) {
287286
// unmarshal packet
288287

289288
var reply MessageCookieReply
290-
reader := bytes.NewReader(elem.packet)
291-
err := binary.Read(reader, binary.LittleEndian, &reply)
289+
err := reply.unmarshal(elem.packet)
292290
if err != nil {
293291
device.log.Verbosef("Failed to decode cookie reply")
294292
goto skip
@@ -353,8 +351,7 @@ func (device *Device) RoutineHandshake(id int) {
353351
// unmarshal
354352

355353
var msg MessageInitiation
356-
reader := bytes.NewReader(elem.packet)
357-
err := binary.Read(reader, binary.LittleEndian, &msg)
354+
err := msg.unmarshal(elem.packet)
358355
if err != nil {
359356
device.log.Errorf("Failed to decode initiation message")
360357
goto skip
@@ -386,8 +383,7 @@ func (device *Device) RoutineHandshake(id int) {
386383
// unmarshal
387384

388385
var msg MessageResponse
389-
reader := bytes.NewReader(elem.packet)
390-
err := binary.Read(reader, binary.LittleEndian, &msg)
386+
err := msg.unmarshal(elem.packet)
391387
if err != nil {
392388
device.log.Errorf("Failed to decode response message")
393389
goto skip

0 commit comments

Comments
 (0)