diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt index 2dbf49d07..1ecef4953 100644 --- a/cmd/k8s-operator/depaware.txt +++ b/cmd/k8s-operator/depaware.txt @@ -838,6 +838,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+ tailscale.com/metrics from tailscale.com/derp+ tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+ + 💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+ tailscale.com/net/connstats from tailscale.com/net/tstun+ tailscale.com/net/dns from tailscale.com/ipn/ipnlocal+ diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 7c4885a4b..07f5958ca 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -311,6 +311,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+ tailscale.com/metrics from tailscale.com/derp+ tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+ + 💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+ tailscale.com/net/connstats from tailscale.com/net/tstun+ tailscale.com/net/dns from tailscale.com/cmd/tailscaled+ diff --git a/cmd/tsidp/depaware.txt b/cmd/tsidp/depaware.txt index b28460352..5e558a0cd 100644 --- a/cmd/tsidp/depaware.txt +++ b/cmd/tsidp/depaware.txt @@ -268,6 +268,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+ tailscale.com/metrics from tailscale.com/derp+ tailscale.com/net/bakedroots from tailscale.com/ipn/ipnlocal+ + 💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+ tailscale.com/net/connstats from tailscale.com/net/tstun+ tailscale.com/net/dns from tailscale.com/ipn/ipnlocal+ diff --git a/net/batching/conn.go b/net/batching/conn.go new file mode 100644 index 000000000..2c6100258 --- /dev/null +++ b/net/batching/conn.go @@ -0,0 +1,48 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Package batching implements a socket optimized for increased throughput. +package batching + +import ( + "net/netip" + + "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" + "tailscale.com/net/packet" + "tailscale.com/types/nettype" +) + +var ( + // This acts as a compile-time check for our usage of ipv6.Message in + // [Conn] for both IPv6 and IPv4 operations. + _ ipv6.Message = ipv4.Message{} +) + +// Conn is a nettype.PacketConn that provides batched i/o using +// platform-specific optimizations, e.g. {recv,send}mmsg & UDP GSO/GRO. +// +// Conn originated from (and is still used by) magicsock where its API was +// strongly influenced by [wireguard-go/conn.Bind] constraints, namely +// wireguard-go's ownership of packet memory. +type Conn interface { + nettype.PacketConn + // ReadBatch reads messages from [Conn] into msgs. It returns the number of + // messages the caller should evaluate for nonzero len, as a zero len + // message may fall on either side of a nonzero. + // + // Each [ipv6.Message.OOB] must be sized to at least MinControlMessageSize(). + // len(msgs) must be at least MinReadBatchMsgsLen(). + ReadBatch(msgs []ipv6.Message, flags int) (n int, err error) + // WriteBatchTo writes buffs to addr. + // + // If geneve.VNI.IsSet(), then geneve is encoded into the space preceding + // offset, and offset must equal [packet.GeneveFixedHeaderLength]. If + // !geneve.VNI.IsSet() then the space preceding offset is ignored. + // + // len(buffs) must be <= batchSize supplied in TryUpgradeToConn(). + // + // WriteBatchTo may return a [neterror.ErrUDPGSODisabled] error if UDP GSO + // was disabled as a result of a send error. + WriteBatchTo(buffs [][]byte, addr netip.AddrPort, geneve packet.GeneveHeader, offset int) error +} diff --git a/net/batching/conn_default.go b/net/batching/conn_default.go new file mode 100644 index 000000000..ed5c494f3 --- /dev/null +++ b/net/batching/conn_default.go @@ -0,0 +1,21 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build !linux + +package batching + +import ( + "tailscale.com/types/nettype" +) + +// TryUpgradeToConn is no-op on all platforms except linux. +func TryUpgradeToConn(pconn nettype.PacketConn, _ string, _ int) nettype.PacketConn { + return pconn +} + +var controlMessageSize = 0 + +func MinControlMessageSize() int { + return controlMessageSize +} diff --git a/wgengine/magicsock/batching_conn_linux.go b/net/batching/conn_linux.go similarity index 88% rename from wgengine/magicsock/batching_conn_linux.go rename to net/batching/conn_linux.go index a0607c624..0416c2729 100644 --- a/wgengine/magicsock/batching_conn_linux.go +++ b/net/batching/conn_linux.go @@ -1,7 +1,7 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package magicsock +package batching import ( "encoding/binary" @@ -43,10 +43,15 @@ type xnetBatchWriter interface { WriteBatch([]ipv6.Message, int) (int, error) } +var ( + // [linuxBatchingConn] implements [Conn]. + _ Conn = &linuxBatchingConn{} +) + // linuxBatchingConn is a UDP socket that provides batched i/o. It implements -// batchingConn. +// [Conn]. type linuxBatchingConn struct { - pc nettype.PacketConn + pc *net.UDPConn xpc xnetBatchReaderWriter rxOffload bool // supports UDP GRO or similar txOffload atomic.Bool // supports UDP GSO or similar @@ -98,9 +103,8 @@ const ( // // All msgs have their Addr field set to addr. // -// All msgs[i].Buffers[0] are preceded by a Geneve header with vni.get() if -// vni.isSet(). -func (c *linuxBatchingConn) coalesceMessages(addr *net.UDPAddr, vni virtualNetworkID, buffs [][]byte, msgs []ipv6.Message, offset int) int { +// All msgs[i].Buffers[0] are preceded by a Geneve header (geneve) if geneve.VNI.IsSet(). +func (c *linuxBatchingConn) coalesceMessages(addr *net.UDPAddr, geneve packet.GeneveHeader, buffs [][]byte, msgs []ipv6.Message, offset int) int { var ( base = -1 // index of msg we are currently coalescing into gsoSize int // segmentation size of msgs[base] @@ -111,15 +115,10 @@ func (c *linuxBatchingConn) coalesceMessages(addr *net.UDPAddr, vni virtualNetwo if addr.IP.To4() == nil { maxPayloadLen = maxIPv6PayloadLen } - vniIsSet := vni.isSet() - var gh packet.GeneveHeader - if vniIsSet { - gh.Protocol = packet.GeneveProtocolWireGuard - gh.VNI = vni.get() - } + vniIsSet := geneve.VNI.IsSet() for i, buff := range buffs { if vniIsSet { - gh.Encode(buffs[i]) + geneve.Encode(buff) } else { buff = buff[offset:] } @@ -179,37 +178,34 @@ func (c *linuxBatchingConn) putSendBatch(batch *sendBatch) { c.sendBatchPool.Put(batch) } -func (c *linuxBatchingConn) WriteBatchTo(buffs [][]byte, addr epAddr, offset int) error { +func (c *linuxBatchingConn) WriteBatchTo(buffs [][]byte, addr netip.AddrPort, geneve packet.GeneveHeader, offset int) error { batch := c.getSendBatch() defer c.putSendBatch(batch) - if addr.ap.Addr().Is6() { - as16 := addr.ap.Addr().As16() + if addr.Addr().Is6() { + as16 := addr.Addr().As16() copy(batch.ua.IP, as16[:]) batch.ua.IP = batch.ua.IP[:16] } else { - as4 := addr.ap.Addr().As4() + as4 := addr.Addr().As4() copy(batch.ua.IP, as4[:]) batch.ua.IP = batch.ua.IP[:4] } - batch.ua.Port = int(addr.ap.Port()) + batch.ua.Port = int(addr.Port()) var ( n int retried bool ) retry: if c.txOffload.Load() { - n = c.coalesceMessages(batch.ua, addr.vni, buffs, batch.msgs, offset) + n = c.coalesceMessages(batch.ua, geneve, buffs, batch.msgs, offset) } else { - vniIsSet := addr.vni.isSet() - var gh packet.GeneveHeader + vniIsSet := geneve.VNI.IsSet() if vniIsSet { - gh.Protocol = packet.GeneveProtocolWireGuard - gh.VNI = addr.vni.get() offset -= packet.GeneveFixedHeaderLength } for i := range buffs { if vniIsSet { - gh.Encode(buffs[i]) + geneve.Encode(buffs[i]) } batch.msgs[i].Buffers[0] = buffs[i][offset:] batch.msgs[i].Addr = batch.ua @@ -231,11 +227,7 @@ retry: } func (c *linuxBatchingConn) SyscallConn() (syscall.RawConn, error) { - sc, ok := c.pc.(syscall.Conn) - if !ok { - return nil, errUnsupportedConnType - } - return sc.SyscallConn() + return c.pc.SyscallConn() } func (c *linuxBatchingConn) writeBatch(msgs []ipv6.Message) error { @@ -391,9 +383,10 @@ func setGSOSizeInControl(control *[]byte, gsoSize uint16) { *control = (*control)[:unix.CmsgSpace(2)] } -// tryUpgradeToBatchingConn probes the capabilities of the OS and pconn, and -// upgrades pconn to a *linuxBatchingConn if appropriate. -func tryUpgradeToBatchingConn(pconn nettype.PacketConn, network string, batchSize int) nettype.PacketConn { +// TryUpgradeToConn probes the capabilities of the OS and pconn, and upgrades +// pconn to a [Conn] if appropriate. A batch size of MinReadBatchMsgsLen() is +// suggested for the best performance. +func TryUpgradeToConn(pconn nettype.PacketConn, network string, batchSize int) nettype.PacketConn { if runtime.GOOS != "linux" { // Exclude Android. return pconn @@ -415,7 +408,7 @@ func tryUpgradeToBatchingConn(pconn nettype.PacketConn, network string, batchSiz return pconn } b := &linuxBatchingConn{ - pc: pconn, + pc: uc, getGSOSizeFromControl: getGSOSizeFromControl, setGSOSizeInControl: setGSOSizeInControl, sendBatchPool: sync.Pool{ @@ -449,3 +442,21 @@ func tryUpgradeToBatchingConn(pconn nettype.PacketConn, network string, batchSiz b.txOffload.Store(txOffload) return b } + +var controlMessageSize = -1 // bomb if used for allocation before init + +func init() { + // controlMessageSize is set to hold a UDP_GRO or UDP_SEGMENT control + // message. These contain a single uint16 of data. + controlMessageSize = unix.CmsgSpace(2) +} + +// MinControlMessageSize returns the minimum control message size required to +// support read batching via [Conn.ReadBatch]. +func MinControlMessageSize() int { + return controlMessageSize +} + +func MinReadBatchMsgsLen() int { + return 128 +} diff --git a/wgengine/magicsock/batching_conn_linux_test.go b/net/batching/conn_linux_test.go similarity index 89% rename from wgengine/magicsock/batching_conn_linux_test.go rename to net/batching/conn_linux_test.go index 7e0ab8fc4..e33ad6d7a 100644 --- a/wgengine/magicsock/batching_conn_linux_test.go +++ b/net/batching/conn_linux_test.go @@ -1,13 +1,14 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package magicsock +package batching import ( "encoding/binary" "net" "testing" + "github.com/tailscale/wireguard-go/conn" "golang.org/x/net/ipv6" "tailscale.com/net/packet" ) @@ -159,13 +160,15 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { return make([]byte, len+packet.GeneveFixedHeaderLength, cap+packet.GeneveFixedHeaderLength) } - vni1 := virtualNetworkID{} - vni1.set(1) + geneve := packet.GeneveHeader{ + Protocol: packet.GeneveProtocolWireGuard, + } + geneve.VNI.Set(1) cases := []struct { name string buffs [][]byte - vni virtualNetworkID + geneve packet.GeneveHeader wantLens []int wantGSO []int }{ @@ -182,7 +185,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { buffs: [][]byte{ withGeneveSpace(1, 1), }, - vni: vni1, + geneve: geneve, wantLens: []int{1 + packet.GeneveFixedHeaderLength}, wantGSO: []int{0}, }, @@ -201,7 +204,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { withGeneveSpace(1, 2+packet.GeneveFixedHeaderLength), withGeneveSpace(1, 1), }, - vni: vni1, + geneve: geneve, wantLens: []int{2 + (2 * packet.GeneveFixedHeaderLength)}, wantGSO: []int{1 + packet.GeneveFixedHeaderLength}, }, @@ -220,7 +223,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { withGeneveSpace(2, 3+packet.GeneveFixedHeaderLength), withGeneveSpace(1, 1), }, - vni: vni1, + geneve: geneve, wantLens: []int{3 + (2 * packet.GeneveFixedHeaderLength)}, wantGSO: []int{2 + packet.GeneveFixedHeaderLength}, }, @@ -241,7 +244,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { withGeneveSpace(1, 1), withGeneveSpace(2, 2), }, - vni: vni1, + geneve: geneve, wantLens: []int{3 + (2 * packet.GeneveFixedHeaderLength), 2 + packet.GeneveFixedHeaderLength}, wantGSO: []int{2 + packet.GeneveFixedHeaderLength, 0}, }, @@ -262,7 +265,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { withGeneveSpace(2, 2), withGeneveSpace(2, 2), }, - vni: vni1, + geneve: geneve, wantLens: []int{4 + (2 * packet.GeneveFixedHeaderLength), 2 + packet.GeneveFixedHeaderLength}, wantGSO: []int{2 + packet.GeneveFixedHeaderLength, 0}, }, @@ -279,7 +282,7 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { msgs[i].Buffers = make([][]byte, 1) msgs[i].OOB = make([]byte, 0, 2) } - got := c.coalesceMessages(addr, tt.vni, tt.buffs, msgs, packet.GeneveFixedHeaderLength) + got := c.coalesceMessages(addr, tt.geneve, tt.buffs, msgs, packet.GeneveFixedHeaderLength) if got != len(tt.wantLens) { t.Fatalf("got len %d want: %d", got, len(tt.wantLens)) } @@ -302,3 +305,12 @@ func Test_linuxBatchingConn_coalesceMessages(t *testing.T) { }) } } + +func TestMinReadBatchMsgsLen(t *testing.T) { + // So long as magicsock uses [Conn], and [wireguard-go/conn.Bind] API is + // shaped for wireguard-go to control packet memory, these values should be + // aligned. + if MinReadBatchMsgsLen() != conn.IdealBatchSize { + t.Fatalf("MinReadBatchMsgsLen():%d != conn.IdealBatchSize(): %d", MinReadBatchMsgsLen(), conn.IdealBatchSize) + } +} diff --git a/net/packet/geneve.go b/net/packet/geneve.go index 29970a8fd..71b365ae8 100644 --- a/net/packet/geneve.go +++ b/net/packet/geneve.go @@ -24,6 +24,33 @@ const ( GeneveProtocolWireGuard uint16 = 0x7A12 ) +// VirtualNetworkID is a Geneve header (RFC8926) 3-byte virtual network +// identifier. Its methods are NOT thread-safe. +type VirtualNetworkID struct { + _vni uint32 +} + +const ( + vniSetMask uint32 = 0xFF000000 + vniGetMask uint32 = ^vniSetMask +) + +// IsSet returns true if Set() had been called previously, otherwise false. +func (v *VirtualNetworkID) IsSet() bool { + return v._vni&vniSetMask != 0 +} + +// Set sets the provided VNI. If VNI exceeds the 3-byte storage it will be +// clamped. +func (v *VirtualNetworkID) Set(vni uint32) { + v._vni = vni | vniSetMask +} + +// Get returns the VNI value. +func (v *VirtualNetworkID) Get() uint32 { + return v._vni & vniGetMask +} + // GeneveHeader represents the fixed size Geneve header from RFC8926. // TLVs/options are not implemented/supported. // @@ -51,7 +78,7 @@ type GeneveHeader struct { // decisions or MAY be used as a mechanism to distinguish between // overlapping address spaces contained in the encapsulated packet when load // balancing across CPUs. - VNI uint32 + VNI VirtualNetworkID // O (1 bit): Control packet. This packet contains a control message. // Control messages are sent between tunnel endpoints. Tunnel endpoints MUST @@ -65,12 +92,18 @@ type GeneveHeader struct { Control bool } -// Encode encodes GeneveHeader into b. If len(b) < GeneveFixedHeaderLength an -// io.ErrShortBuffer error is returned. +var ErrGeneveVNIUnset = errors.New("VNI is unset") + +// Encode encodes GeneveHeader into b. If len(b) < [GeneveFixedHeaderLength] an +// [io.ErrShortBuffer] error is returned. If !h.VNI.IsSet() then an +// [ErrGeneveVNIUnset] error is returned. func (h *GeneveHeader) Encode(b []byte) error { if len(b) < GeneveFixedHeaderLength { return io.ErrShortBuffer } + if !h.VNI.IsSet() { + return ErrGeneveVNIUnset + } if h.Version > 3 { return errors.New("version must be <= 3") } @@ -81,15 +114,12 @@ func (h *GeneveHeader) Encode(b []byte) error { b[1] |= 0x80 } binary.BigEndian.PutUint16(b[2:], h.Protocol) - if h.VNI > 1<<24-1 { - return errors.New("VNI must be <= 2^24-1") - } - binary.BigEndian.PutUint32(b[4:], h.VNI<<8) + binary.BigEndian.PutUint32(b[4:], h.VNI.Get()<<8) return nil } -// Decode decodes GeneveHeader from b. If len(b) < GeneveFixedHeaderLength an -// io.ErrShortBuffer error is returned. +// Decode decodes GeneveHeader from b. If len(b) < [GeneveFixedHeaderLength] an +// [io.ErrShortBuffer] error is returned. func (h *GeneveHeader) Decode(b []byte) error { if len(b) < GeneveFixedHeaderLength { return io.ErrShortBuffer @@ -99,6 +129,6 @@ func (h *GeneveHeader) Decode(b []byte) error { h.Control = true } h.Protocol = binary.BigEndian.Uint16(b[2:]) - h.VNI = binary.BigEndian.Uint32(b[4:]) >> 8 + h.VNI.Set(binary.BigEndian.Uint32(b[4:]) >> 8) return nil } diff --git a/net/packet/geneve_test.go b/net/packet/geneve_test.go index 029638638..be9784998 100644 --- a/net/packet/geneve_test.go +++ b/net/packet/geneve_test.go @@ -4,18 +4,21 @@ package packet import ( + "math" "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "tailscale.com/types/ptr" ) func TestGeneveHeader(t *testing.T) { in := GeneveHeader{ Version: 3, Protocol: GeneveProtocolDisco, - VNI: 1<<24 - 1, Control: true, } + in.VNI.Set(1<<24 - 1) b := make([]byte, GeneveFixedHeaderLength) err := in.Encode(b) if err != nil { @@ -26,7 +29,56 @@ func TestGeneveHeader(t *testing.T) { if err != nil { t.Fatal(err) } - if diff := cmp.Diff(out, in); diff != "" { + if diff := cmp.Diff(out, in, cmpopts.EquateComparable(VirtualNetworkID{})); diff != "" { t.Fatalf("wrong results (-got +want)\n%s", diff) } } + +func TestVirtualNetworkID(t *testing.T) { + tests := []struct { + name string + set *uint32 + want uint32 + }{ + { + "don't Set", + nil, + 0, + }, + { + "Set 0", + ptr.To(uint32(0)), + 0, + }, + { + "Set 1", + ptr.To(uint32(1)), + 1, + }, + { + "Set math.MaxUint32", + ptr.To(uint32(math.MaxUint32)), + 1<<24 - 1, + }, + { + "Set max 3-byte value", + ptr.To(uint32(1<<24 - 1)), + 1<<24 - 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := VirtualNetworkID{} + if tt.set != nil { + v.Set(*tt.set) + } + if v.IsSet() != (tt.set != nil) { + t.Fatalf("IsSet: %v != wantIsSet: %v", v.IsSet(), tt.set != nil) + } + if v.Get() != tt.want { + t.Fatalf("Get(): %v != want: %v", v.Get(), tt.want) + } + }) + } +} diff --git a/net/udprelay/server.go b/net/udprelay/server.go index aece3bc59..e138c33f2 100644 --- a/net/udprelay/server.go +++ b/net/udprelay/server.go @@ -140,7 +140,8 @@ func (e *serverEndpoint) handleDiscoControlMsg(from netip.AddrPort, senderIndex rand.Read(e.challenge[senderIndex][:]) copy(m.Challenge[:], e.challenge[senderIndex][:]) reply := make([]byte, packet.GeneveFixedHeaderLength, 512) - gh := packet.GeneveHeader{Control: true, VNI: e.vni, Protocol: packet.GeneveProtocolDisco} + gh := packet.GeneveHeader{Control: true, Protocol: packet.GeneveProtocolDisco} + gh.VNI.Set(e.vni) err = gh.Encode(reply) if err != nil { return @@ -543,7 +544,7 @@ func (s *Server) handlePacket(from netip.AddrPort, b []byte, rxSocket, otherAFSo // it simple (and slow) for now. s.mu.Lock() defer s.mu.Unlock() - e, ok := s.byVNI[gh.VNI] + e, ok := s.byVNI[gh.VNI.Get()] if !ok { // unknown VNI return diff --git a/net/udprelay/server_test.go b/net/udprelay/server_test.go index de1c29364..8fc4a4f78 100644 --- a/net/udprelay/server_test.go +++ b/net/udprelay/server_test.go @@ -62,7 +62,8 @@ func (c *testClient) read(t *testing.T) []byte { func (c *testClient) writeDataPkt(t *testing.T, b []byte) { pkt := make([]byte, packet.GeneveFixedHeaderLength, packet.GeneveFixedHeaderLength+len(b)) - gh := packet.GeneveHeader{Control: false, VNI: c.vni, Protocol: packet.GeneveProtocolWireGuard} + gh := packet.GeneveHeader{Control: false, Protocol: packet.GeneveProtocolWireGuard} + gh.VNI.Set(c.vni) err := gh.Encode(pkt) if err != nil { t.Fatal(err) @@ -84,7 +85,7 @@ func (c *testClient) readDataPkt(t *testing.T) []byte { if gh.Control { t.Fatal("unexpected control") } - if gh.VNI != c.vni { + if gh.VNI.Get() != c.vni { t.Fatal("unexpected vni") } return b[packet.GeneveFixedHeaderLength:] @@ -92,7 +93,8 @@ func (c *testClient) readDataPkt(t *testing.T) []byte { func (c *testClient) writeControlDiscoMsg(t *testing.T, msg disco.Message) { pkt := make([]byte, packet.GeneveFixedHeaderLength, 512) - gh := packet.GeneveHeader{Control: true, VNI: c.vni, Protocol: packet.GeneveProtocolDisco} + gh := packet.GeneveHeader{Control: true, Protocol: packet.GeneveProtocolDisco} + gh.VNI.Set(c.vni) err := gh.Encode(pkt) if err != nil { t.Fatal(err) @@ -117,7 +119,7 @@ func (c *testClient) readControlDiscoMsg(t *testing.T) disco.Message { if !gh.Control { t.Fatal("unexpected non-control") } - if gh.VNI != c.vni { + if gh.VNI.Get() != c.vni { t.Fatal("unexpected vni") } b = b[packet.GeneveFixedHeaderLength:] diff --git a/tsnet/depaware.txt b/tsnet/depaware.txt index da3175b8c..9ad340c90 100644 --- a/tsnet/depaware.txt +++ b/tsnet/depaware.txt @@ -264,6 +264,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) tailscale.com/logtail/filch from tailscale.com/log/sockstatlog+ tailscale.com/metrics from tailscale.com/derp+ tailscale.com/net/bakedroots from tailscale.com/ipn/ipnlocal+ + 💣 tailscale.com/net/batching from tailscale.com/wgengine/magicsock tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+ tailscale.com/net/connstats from tailscale.com/net/tstun+ tailscale.com/net/dns from tailscale.com/ipn/ipnlocal+ diff --git a/wgengine/magicsock/batching_conn.go b/wgengine/magicsock/batching_conn.go deleted file mode 100644 index b769907db..000000000 --- a/wgengine/magicsock/batching_conn.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Tailscale Inc & AUTHORS -// SPDX-License-Identifier: BSD-3-Clause - -package magicsock - -import ( - "golang.org/x/net/ipv4" - "golang.org/x/net/ipv6" - "tailscale.com/types/nettype" -) - -var ( - // This acts as a compile-time check for our usage of ipv6.Message in - // batchingConn for both IPv6 and IPv4 operations. - _ ipv6.Message = ipv4.Message{} -) - -// batchingConn is a nettype.PacketConn that provides batched i/o. -type batchingConn interface { - nettype.PacketConn - ReadBatch(msgs []ipv6.Message, flags int) (n int, err error) - WriteBatchTo(buffs [][]byte, addr epAddr, offset int) error -} diff --git a/wgengine/magicsock/batching_conn_default.go b/wgengine/magicsock/batching_conn_default.go deleted file mode 100644 index 519cf8082..000000000 --- a/wgengine/magicsock/batching_conn_default.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Tailscale Inc & AUTHORS -// SPDX-License-Identifier: BSD-3-Clause - -//go:build !linux - -package magicsock - -import ( - "tailscale.com/types/nettype" -) - -func tryUpgradeToBatchingConn(pconn nettype.PacketConn, _ string, _ int) nettype.PacketConn { - return pconn -} diff --git a/wgengine/magicsock/debughttp.go b/wgengine/magicsock/debughttp.go index cfdf8c1e1..a0159d21e 100644 --- a/wgengine/magicsock/debughttp.go +++ b/wgengine/magicsock/debughttp.go @@ -152,7 +152,7 @@ func printEndpointHTML(w io.Writer, ep *endpoint) { io.WriteString(w, "

Endpoints: