Apply Tailscale bind send headroom
This commit is contained in:
parent
45cd03b8a1
commit
749db0015c
7 changed files with 50 additions and 32 deletions
|
|
@ -334,7 +334,7 @@ func (e ErrUDPGSODisabled) Unwrap() error {
|
||||||
return e.RetryErr
|
return e.RetryErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error {
|
func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint, offset int) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
blackhole := s.blackhole4
|
blackhole := s.blackhole4
|
||||||
conn := s.ipv4
|
conn := s.ipv4
|
||||||
|
|
@ -377,7 +377,7 @@ func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error {
|
||||||
)
|
)
|
||||||
retry:
|
retry:
|
||||||
if offload {
|
if offload {
|
||||||
n := coalesceMessages(ua, endpoint.(*StdNetEndpoint), bufs, *msgs, setGSOSize)
|
n := coalesceMessages(ua, endpoint.(*StdNetEndpoint), bufs, offset, *msgs, setGSOSize)
|
||||||
err = s.send(conn, br, (*msgs)[:n])
|
err = s.send(conn, br, (*msgs)[:n])
|
||||||
if err != nil && offload && errShouldDisableUDPGSO(err) {
|
if err != nil && offload && errShouldDisableUDPGSO(err) {
|
||||||
offload = false
|
offload = false
|
||||||
|
|
@ -394,7 +394,7 @@ retry:
|
||||||
} else {
|
} else {
|
||||||
for i := range bufs {
|
for i := range bufs {
|
||||||
(*msgs)[i].Addr = ua
|
(*msgs)[i].Addr = ua
|
||||||
(*msgs)[i].Buffers[0] = bufs[i]
|
(*msgs)[i].Buffers[0] = bufs[i][offset:]
|
||||||
setSrcControl(&(*msgs)[i].OOB, endpoint.(*StdNetEndpoint))
|
setSrcControl(&(*msgs)[i].OOB, endpoint.(*StdNetEndpoint))
|
||||||
}
|
}
|
||||||
err = s.send(conn, br, (*msgs)[:len(bufs)])
|
err = s.send(conn, br, (*msgs)[:len(bufs)])
|
||||||
|
|
@ -443,7 +443,7 @@ const (
|
||||||
|
|
||||||
type setGSOFunc func(control *[]byte, gsoSize uint16)
|
type setGSOFunc func(control *[]byte, gsoSize uint16)
|
||||||
|
|
||||||
func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, msgs []ipv6.Message, setGSO setGSOFunc) int {
|
func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, offset int, msgs []ipv6.Message, setGSO setGSOFunc) int {
|
||||||
var (
|
var (
|
||||||
base = -1 // index of msg we are currently coalescing into
|
base = -1 // index of msg we are currently coalescing into
|
||||||
gsoSize int // segmentation size of msgs[base]
|
gsoSize int // segmentation size of msgs[base]
|
||||||
|
|
@ -455,6 +455,7 @@ func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, msgs
|
||||||
maxPayloadLen = maxIPv6PayloadLen
|
maxPayloadLen = maxIPv6PayloadLen
|
||||||
}
|
}
|
||||||
for i, buf := range bufs {
|
for i, buf := range bufs {
|
||||||
|
buf = buf[offset:]
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
msgLen := len(buf)
|
msgLen := len(buf)
|
||||||
baseLenBefore := len(msgs[base].Buffers[0])
|
baseLenBefore := len(msgs[base].Buffers[0])
|
||||||
|
|
|
||||||
|
|
@ -485,7 +485,7 @@ func (bind *afWinRingBind) Send(buf []byte, nend *WinRingEndpoint, isOpen *atomi
|
||||||
return winrio.SendEx(bind.rq, dataBuffer, 1, nil, addressBuffer, nil, nil, 0, 0)
|
return winrio.SendEx(bind.rq, dataBuffer, 1, nil, addressBuffer, nil, nil, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bind *WinRingBind) Send(bufs [][]byte, endpoint Endpoint) error {
|
func (bind *WinRingBind) Send(bufs [][]byte, endpoint Endpoint, offset int) error {
|
||||||
nend, ok := endpoint.(*WinRingEndpoint)
|
nend, ok := endpoint.(*WinRingEndpoint)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrWrongEndpointType
|
return ErrWrongEndpointType
|
||||||
|
|
@ -493,6 +493,7 @@ func (bind *WinRingBind) Send(bufs [][]byte, endpoint Endpoint) error {
|
||||||
bind.mu.RLock()
|
bind.mu.RLock()
|
||||||
defer bind.mu.RUnlock()
|
defer bind.mu.RUnlock()
|
||||||
for _, buf := range bufs {
|
for _, buf := range bufs {
|
||||||
|
buf = buf[offset:]
|
||||||
switch nend.family {
|
switch nend.family {
|
||||||
case windows.AF_INET:
|
case windows.AF_INET:
|
||||||
if bind.v4.blackhole {
|
if bind.v4.blackhole {
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,11 @@ type Bind interface {
|
||||||
// This mark is passed to the kernel as the socket option SO_MARK.
|
// This mark is passed to the kernel as the socket option SO_MARK.
|
||||||
SetMark(mark uint32) error
|
SetMark(mark uint32) error
|
||||||
|
|
||||||
// Send writes one or more packets in bufs to address ep. The length of
|
// Send writes one or more packets in bufs to address ep. A nonzero offset
|
||||||
// bufs must not exceed BatchSize().
|
// can be used to instruct the Bind on where packet data begins in each
|
||||||
Send(bufs [][]byte, ep Endpoint) error
|
// element of the bufs slice. Space preceding offset is free to use for
|
||||||
|
// additional encapsulation. The length of bufs must not exceed BatchSize().
|
||||||
|
Send(bufs [][]byte, ep Endpoint, offset int) error
|
||||||
|
|
||||||
// ParseEndpoint creates a new endpoint from a string.
|
// ParseEndpoint creates a new endpoint from a string.
|
||||||
ParseEndpoint(s string) (Endpoint, error)
|
ParseEndpoint(s string) (Endpoint, error)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const (
|
||||||
const (
|
const (
|
||||||
MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive)
|
MinMessageSize = MessageKeepaliveSize // minimum size of transport message (keepalive)
|
||||||
MaxMessageSize = MaxSegmentSize // maximum size of transport message
|
MaxMessageSize = MaxSegmentSize // maximum size of transport message
|
||||||
MaxContentSize = MaxSegmentSize - MessageTransportSize // maximum size of transport message content
|
MaxContentSize = MaxSegmentSize - MessageTransportSize - MessageEncapsulatingTransportSize // maximum size of transport message content
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Implementation constants */
|
/* Implementation constants */
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ const (
|
||||||
MessageResponseSize = 92 // size of response message
|
MessageResponseSize = 92 // size of response message
|
||||||
MessageCookieReplySize = 64 // size of cookie reply message
|
MessageCookieReplySize = 64 // size of cookie reply message
|
||||||
MessageTransportHeaderSize = 16 // size of data preceding content in transport message
|
MessageTransportHeaderSize = 16 // size of data preceding content in transport message
|
||||||
|
MessageEncapsulatingTransportSize = 8 // size of optional, free (for use by conn.Bind.Send()) space preceding the transport header
|
||||||
MessageTransportSize = MessageTransportHeaderSize + poly1305.TagSize // size of empty transport
|
MessageTransportSize = MessageTransportHeaderSize + poly1305.TagSize // size of empty transport
|
||||||
MessageKeepaliveSize = MessageTransportSize // size of keepalive
|
MessageKeepaliveSize = MessageTransportSize // size of keepalive
|
||||||
MessageHandshakeSize = MessageInitiationSize // size of largest handshake related message
|
MessageHandshakeSize = MessageInitiationSize // size of largest handshake related message
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,9 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
||||||
return peer, nil
|
return peer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendBuffers sends buffers to peer. WireGuard packet data in each element of
|
||||||
|
// buffers must be preceded by MessageEncapsulatingTransportSize number of
|
||||||
|
// bytes.
|
||||||
func (peer *Peer) SendBuffers(buffers [][]byte) error {
|
func (peer *Peer) SendBuffers(buffers [][]byte) error {
|
||||||
peer.device.net.RLock()
|
peer.device.net.RLock()
|
||||||
defer peer.device.net.RUnlock()
|
defer peer.device.net.RUnlock()
|
||||||
|
|
@ -133,7 +136,7 @@ func (peer *Peer) SendBuffers(buffers [][]byte) error {
|
||||||
}
|
}
|
||||||
peer.endpoint.Unlock()
|
peer.endpoint.Unlock()
|
||||||
|
|
||||||
err := peer.device.net.bind.Send(buffers, endpoint)
|
err := peer.device.net.bind.Send(buffers, endpoint, MessageEncapsulatingTransportSize)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var totalLen uint64
|
var totalLen uint64
|
||||||
for _, b := range buffers {
|
for _, b := range buffers {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,11 @@ import (
|
||||||
|
|
||||||
type QueueOutboundElement struct {
|
type QueueOutboundElement struct {
|
||||||
buffer *[MaxMessageSize]byte // slice holding the packet data
|
buffer *[MaxMessageSize]byte // slice holding the packet data
|
||||||
packet []byte // slice of "buffer" (always!)
|
// packet is always a slice of "buffer". The starting offset in buffer
|
||||||
|
// is either:
|
||||||
|
// a) MessageEncapsulatingTransportSize+MessageTransportHeaderSize (plaintext)
|
||||||
|
// b) 0 (post-encryption)
|
||||||
|
packet []byte
|
||||||
nonce uint64 // nonce for encryption
|
nonce uint64 // nonce for encryption
|
||||||
keypair *Keypair // keypair for encryption
|
keypair *Keypair // keypair for encryption
|
||||||
peer *Peer // related peer
|
peer *Peer // related peer
|
||||||
|
|
@ -123,14 +127,15 @@ func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := make([]byte, MessageInitiationSize)
|
buf := make([]byte, MessageEncapsulatingTransportSize+MessageInitiationSize)
|
||||||
|
packet := buf[MessageEncapsulatingTransportSize:]
|
||||||
_ = msg.marshal(packet)
|
_ = msg.marshal(packet)
|
||||||
peer.cookieGenerator.AddMacs(packet)
|
peer.cookieGenerator.AddMacs(packet)
|
||||||
|
|
||||||
peer.timersAnyAuthenticatedPacketTraversal()
|
peer.timersAnyAuthenticatedPacketTraversal()
|
||||||
peer.timersAnyAuthenticatedPacketSent()
|
peer.timersAnyAuthenticatedPacketSent()
|
||||||
|
|
||||||
err = peer.SendBuffers([][]byte{packet})
|
err = peer.SendBuffers([][]byte{buf})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
peer.device.log.Errorf("%v - Failed to send handshake initiation: %v", peer, err)
|
peer.device.log.Errorf("%v - Failed to send handshake initiation: %v", peer, err)
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +157,8 @@ func (peer *Peer) SendHandshakeResponse() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := make([]byte, MessageResponseSize)
|
buf := make([]byte, MessageEncapsulatingTransportSize+MessageResponseSize)
|
||||||
|
packet := buf[MessageEncapsulatingTransportSize:]
|
||||||
_ = response.marshal(packet)
|
_ = response.marshal(packet)
|
||||||
peer.cookieGenerator.AddMacs(packet)
|
peer.cookieGenerator.AddMacs(packet)
|
||||||
|
|
||||||
|
|
@ -167,7 +173,7 @@ func (peer *Peer) SendHandshakeResponse() error {
|
||||||
peer.timersAnyAuthenticatedPacketSent()
|
peer.timersAnyAuthenticatedPacketSent()
|
||||||
|
|
||||||
// TODO: allocation could be avoided
|
// TODO: allocation could be avoided
|
||||||
err = peer.SendBuffers([][]byte{packet})
|
err = peer.SendBuffers([][]byte{buf})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
peer.device.log.Errorf("%v - Failed to send handshake response: %v", peer, err)
|
peer.device.log.Errorf("%v - Failed to send handshake response: %v", peer, err)
|
||||||
}
|
}
|
||||||
|
|
@ -184,10 +190,11 @@ func (device *Device) SendHandshakeCookie(initiatingElem *QueueHandshakeElement)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := make([]byte, MessageCookieReplySize)
|
buf := make([]byte, MessageEncapsulatingTransportSize+MessageCookieReplySize)
|
||||||
|
packet := buf[MessageEncapsulatingTransportSize:]
|
||||||
_ = reply.marshal(packet)
|
_ = reply.marshal(packet)
|
||||||
// TODO: allocation could be avoided
|
// TODO: allocation could be avoided
|
||||||
device.net.bind.Send([][]byte{packet}, initiatingElem.endpoint)
|
device.net.bind.Send([][]byte{buf}, initiatingElem.endpoint, MessageEncapsulatingTransportSize)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +227,7 @@ func (device *Device) RoutineReadFromTUN() {
|
||||||
elemsByPeer = make(map[*Peer]*QueueOutboundElementsContainer, batchSize)
|
elemsByPeer = make(map[*Peer]*QueueOutboundElementsContainer, batchSize)
|
||||||
count = 0
|
count = 0
|
||||||
sizes = make([]int, batchSize)
|
sizes = make([]int, batchSize)
|
||||||
offset = MessageTransportHeaderSize
|
offset = MessageEncapsulatingTransportSize + MessageTransportHeaderSize
|
||||||
)
|
)
|
||||||
|
|
||||||
for i := range elems {
|
for i := range elems {
|
||||||
|
|
@ -446,7 +453,7 @@ func (device *Device) RoutineEncryption(id int) {
|
||||||
for elemsContainer := range device.queue.encryption.c {
|
for elemsContainer := range device.queue.encryption.c {
|
||||||
for _, elem := range elemsContainer.elems {
|
for _, elem := range elemsContainer.elems {
|
||||||
// populate header fields
|
// populate header fields
|
||||||
header := elem.buffer[:MessageTransportHeaderSize]
|
header := elem.buffer[MessageEncapsulatingTransportSize : MessageEncapsulatingTransportSize+MessageTransportHeaderSize]
|
||||||
|
|
||||||
fieldType := header[0:4]
|
fieldType := header[0:4]
|
||||||
fieldReceiver := header[4:8]
|
fieldReceiver := header[4:8]
|
||||||
|
|
@ -469,6 +476,9 @@ func (device *Device) RoutineEncryption(id int) {
|
||||||
elem.packet,
|
elem.packet,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// re-slice packet to include encapsulating transport space
|
||||||
|
elem.packet = elem.buffer[:MessageEncapsulatingTransportSize+len(elem.packet)]
|
||||||
}
|
}
|
||||||
elemsContainer.Unlock()
|
elemsContainer.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue