From d098437d56d3649b83188e89fbb407019a2fdc1f Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Sun, 11 Dec 2022 19:39:55 +0900 Subject: [PATCH] go.mod: gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2 Signed-off-by: Akihiro Suda --- go.mod | 2 +- go.sum | 4 +- pkg/tap/link.go | 8 +- pkg/tap/switch.go | 14 +- .../atomicbitops_state_autogen.go | 33 ++ .../gvisor/pkg/atomicbitops/bool.go | 71 +++ .../gvisor.dev/gvisor/pkg/bufferv2/buffer.go | 20 + .../pkg/bufferv2/bufferv2_state_autogen.go | 2 +- .../gvisor.dev/gvisor/pkg/bufferv2/chunk.go | 12 +- .../gvisor/pkg/bufferv2/chunk_refs.go | 20 +- vendor/gvisor.dev/gvisor/pkg/bufferv2/view.go | 2 +- .../gvisor.dev/gvisor/pkg/context/context.go | 8 +- vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go | 2 +- .../pkg/cpuid/cpuid_amd64_state_autogen.go | 2 +- vendor/gvisor.dev/gvisor/pkg/log/glog.go | 2 +- vendor/gvisor.dev/gvisor/pkg/log/json.go | 2 +- vendor/gvisor.dev/gvisor/pkg/log/json_k8s.go | 2 +- vendor/gvisor.dev/gvisor/pkg/log/log.go | 63 ++- .../gvisor.dev/gvisor/pkg/log/rate_limited.go | 6 +- .../gvisor.dev/gvisor/pkg/refs/refcounter.go | 367 +----------- .../gvisor/pkg/refs/refcounter_state.go | 35 -- .../gvisor/pkg/{refsvfs2 => refs}/refs_map.go | 32 +- .../gvisor/pkg/refs/refs_state_autogen.go | 154 ----- vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs.go | 41 -- .../pkg/sleep/sleep_unsafe_state_autogen.go | 4 +- .../gvisor/pkg/state/deferred_list.go | 51 +- vendor/gvisor.dev/gvisor/pkg/state/encode.go | 5 - vendor/gvisor.dev/gvisor/pkg/state/state.go | 20 +- vendor/gvisor.dev/gvisor/pkg/state/types.go | 2 +- .../gvisor/pkg/sync/checklocks_on_unsafe.go | 2 +- .../locking/atomicptrmap_ancestors_unsafe.go | 446 +++++++++++++++ .../locking/atomicptrmap_goroutine_unsafe.go | 446 +++++++++++++++ .../gvisor/pkg/sync/locking/lockdep.go | 174 ++++++ .../gvisor/pkg/sync/locking/lockdep_norace.go | 42 ++ .../gvisor/pkg/sync/locking/locking.go | 28 + .../gvisor/pkg/sync/mutex_unsafe.go | 35 +- .../gvisor/pkg/sync/runtime_unsafe.go | 4 +- .../gvisor/pkg/tcpip/adapters/gonet/gonet.go | 3 + .../gvisor/pkg/tcpip/checksum/checksum.go | 216 +++++++ .../checksum/checksum_state_autogen.go} | 2 +- vendor/gvisor.dev/gvisor/pkg/tcpip/errors.go | 12 +- .../gvisor/pkg/tcpip/header/checksum.go | 219 +------- .../gvisor/pkg/tcpip/header/datagram.go | 18 + .../gvisor/pkg/tcpip/header/icmpv4.go | 9 +- .../gvisor/pkg/tcpip/header/icmpv6.go | 11 +- .../gvisor/pkg/tcpip/header/igmp.go | 3 +- .../gvisor/pkg/tcpip/header/ipv4.go | 13 +- .../gvisor/pkg/tcpip/header/parse/parse.go | 14 +- .../gvisor.dev/gvisor/pkg/tcpip/header/tcp.go | 17 +- .../gvisor.dev/gvisor/pkg/tcpip/header/udp.go | 9 +- .../gvisor/pkg/tcpip/link/nested/nested.go | 6 +- .../gvisor/pkg/tcpip/link/sniffer/pcap.go | 2 +- .../gvisor/pkg/tcpip/link/sniffer/sniffer.go | 8 +- .../gvisor/pkg/tcpip/network/arp/arp.go | 8 +- .../internal/fragmentation/fragmentation.go | 30 +- .../internal/fragmentation/reassembler.go | 20 +- .../pkg/tcpip/network/internal/ip/errors.go | 8 +- .../internal/ip/generic_multicast_protocol.go | 239 +++----- .../network/internal/multicast/route_table.go | 8 +- .../gvisor/pkg/tcpip/network/ipv4/icmp.go | 20 +- .../gvisor/pkg/tcpip/network/ipv4/igmp.go | 6 +- .../gvisor/pkg/tcpip/network/ipv4/ipv4.go | 87 +-- .../gvisor.dev/gvisor/pkg/tcpip/socketops.go | 2 +- .../pkg/tcpip/stack/address_state_mutex.go | 96 ++++ .../pkg/tcpip/stack/address_state_refs.go | 140 +++++ .../tcpip/stack/addressable_endpoint_state.go | 54 +- .../stack/addressable_endpoint_state_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/bucket_mutex.go | 98 ++++ .../tcpip/stack/cleanup_endpoints_mutex.go | 64 +++ .../gvisor/pkg/tcpip/stack/conn_mutex.go | 96 ++++ .../pkg/tcpip/stack/conn_track_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/conntrack.go | 63 +-- .../pkg/tcpip/stack/endpoints_by_nic_mutex.go | 96 ++++ .../gvisor.dev/gvisor/pkg/tcpip/stack/gro.go | 530 ++++++++++++++++++ .../stack/gro_packet_list.go} | 86 +-- .../gvisor/pkg/tcpip/stack/iptables.go | 39 +- .../gvisor/pkg/tcpip/stack/iptables_mutex.go | 96 ++++ .../pkg/tcpip/stack/iptables_targets.go | 32 +- .../gvisor/pkg/tcpip/stack/iptables_types.go | 9 +- .../tcpip/stack/multi_port_endpoint_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/neighbor_cache.go | 32 +- .../pkg/tcpip/stack/neighbor_cache_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/neighbor_entry.go | 73 ++- .../pkg/tcpip/stack/neighbor_entry_mutex.go | 96 ++++ .../gvisor.dev/gvisor/pkg/tcpip/stack/nic.go | 166 +++--- .../gvisor/pkg/tcpip/stack/nic_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/nic_stats.go | 6 +- .../gvisor/pkg/tcpip/stack/packet_buffer.go | 140 +++-- .../pkg/tcpip/stack/packet_buffer_list.go | 8 +- .../pkg/tcpip/stack/packet_buffer_refs.go | 22 +- .../pkg/tcpip/stack/packet_buffer_unsafe.go | 10 +- .../tcpip/stack/packet_endpoint_list_mutex.go | 96 ++++ .../pkg/tcpip/stack/packet_eps_mutex.go | 96 ++++ .../packets_pending_link_resolution_mutex.go | 64 +++ .../gvisor/pkg/tcpip/stack/pending_packets.go | 9 +- .../gvisor/pkg/tcpip/stack/registration.go | 42 +- .../gvisor/pkg/tcpip/stack/route.go | 49 +- .../gvisor/pkg/tcpip/stack/route_mutex.go | 96 ++++ .../pkg/tcpip/stack/route_stack_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/stack.go | 82 ++- .../gvisor/pkg/tcpip/stack/stack_mutex.go | 96 ++++ .../gvisor/pkg/tcpip/stack/stack_options.go | 4 +- .../pkg/tcpip/stack/stack_state_autogen.go | 131 ++++- .../pkg/tcpip/stack/state_conn_mutex.go | 96 ++++ .../pkg/tcpip/stack/transport_demuxer.go | 23 +- .../tcpip/stack/transport_endpoints_mutex.go | 96 ++++ vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go | 10 + .../gvisor/pkg/tcpip/tcpip_state_autogen.go | 18 +- .../pkg/tcpip/transport/icmp/endpoint.go | 26 +- .../transport/icmp/icmp_state_autogen.go | 2 +- .../pkg/tcpip/transport/icmp/protocol.go | 4 +- .../transport/internal/network/endpoint.go | 57 +- .../tcpip/transport/internal/noop/endpoint.go | 2 +- .../pkg/tcpip/transport/packet/endpoint.go | 9 +- .../transport/packet/packet_state_autogen.go | 2 +- .../pkg/tcpip/transport/raw/endpoint.go | 29 +- .../tcpip/transport/raw/raw_state_autogen.go | 2 +- .../gvisor/pkg/tcpip/transport/tcp/connect.go | 15 +- .../pkg/tcpip/transport/tcp/dispatcher.go | 14 +- .../pkg/tcpip/transport/tcp/endpoint.go | 45 +- .../pkg/tcpip/transport/tcp/forwarder.go | 2 +- .../pkg/tcpip/transport/tcp/protocol.go | 6 +- .../gvisor/pkg/tcpip/transport/tcp/segment.go | 16 +- .../pkg/tcpip/transport/tcp/segment_heap.go | 4 +- .../gvisor/pkg/tcpip/transport/tcp/snd.go | 2 +- .../tcpip/transport/tcp/tcp_segment_refs.go | 20 +- .../tcpip/transport/tcp/tcp_state_autogen.go | 6 +- .../pkg/tcpip/transport/udp/endpoint.go | 26 +- .../pkg/tcpip/transport/udp/forwarder.go | 4 +- .../pkg/tcpip/transport/udp/protocol.go | 8 +- .../tcpip/transport/udp/udp_state_autogen.go | 2 +- vendor/modules.txt | 7 +- 132 files changed, 5289 insertions(+), 1810 deletions(-) create mode 100644 vendor/gvisor.dev/gvisor/pkg/atomicbitops/bool.go delete mode 100644 vendor/gvisor.dev/gvisor/pkg/refs/refcounter_state.go rename vendor/gvisor.dev/gvisor/pkg/{refsvfs2 => refs}/refs_map.go (88%) delete mode 100644 vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_ancestors_unsafe.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_goroutine_unsafe.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep_norace.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/sync/locking/locking.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum.go rename vendor/gvisor.dev/gvisor/pkg/{refsvfs2/refsvfs2_state_autogen.go => tcpip/checksum/checksum_state_autogen.go} (70%) create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/header/datagram.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_refs.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/bucket_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/cleanup_endpoints_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_track_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/endpoints_by_nic_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro.go rename vendor/gvisor.dev/gvisor/pkg/{refs/weak_ref_list.go => tcpip/stack/gro_packet_list.go} (61%) create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/multi_port_endpoint_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_endpoint_list_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_eps_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packets_pending_link_resolution_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_stack_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/state_conn_mutex.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_endpoints_mutex.go diff --git a/go.mod b/go.mod index 1dd10f6c5..42db18cad 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa golang.org/x/sync v0.1.0 golang.org/x/sys v0.3.0 - gvisor.dev/gvisor v0.0.0-20220908032458-edc830a43ba6 + gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2 inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 ) diff --git a/go.sum b/go.sum index 61796d726..12867f076 100644 --- a/go.sum +++ b/go.sum @@ -209,7 +209,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gvisor.dev/gvisor v0.0.0-20220908032458-edc830a43ba6 h1:Aq4piePGzmo0ij3yfseJ0rj9W8jxSJgRfiA9QMWngdA= -gvisor.dev/gvisor v0.0.0-20220908032458-edc830a43ba6/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= +gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2 h1:QN+Xh63jThYFN4CrcD4KXj+rUhevlb0LXEAlZ4m+qXQ= +gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 h1:PqdHrvQRVK1zapJkd0qf6+tevvSIcWdfenVqJd3PHWU= inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0/go.mod h1:Tojt5kmHpDIR2jMojxzZK2w2ZR7OILODmUo2gaSwjrk= diff --git a/pkg/tap/link.go b/pkg/tap/link.go index ad44b0359..c5ff3a788 100644 --- a/pkg/tap/link.go +++ b/pkg/tap/link.go @@ -56,11 +56,11 @@ func (e *LinkEndpoint) IsAttached() bool { return e.dispatcher != nil } -func (e *LinkEndpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func (e *LinkEndpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { e.dispatcher.DeliverNetworkPacket(protocol, pkt) } -func (e *LinkEndpoint) AddHeader(pkt *stack.PacketBuffer) { +func (e *LinkEndpoint) AddHeader(pkt stack.PacketBufferPtr) { } func (e *LinkEndpoint) Capabilities() stack.LinkEndpointCapabilities { @@ -93,7 +93,7 @@ func (e *LinkEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Err return n, nil } -func (e *LinkEndpoint) writePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error { +func (e *LinkEndpoint) writePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) tcpip.Error { // Preserve the src address if it's set in the route. srcAddr := e.LinkAddress() if r.LocalLinkAddress != "" { @@ -126,7 +126,7 @@ func (e *LinkEndpoint) writePacket(r stack.RouteInfo, protocol tcpip.NetworkProt return nil } -func (e *LinkEndpoint) WriteRawPacket(pkt *stack.PacketBuffer) tcpip.Error { +func (e *LinkEndpoint) WriteRawPacket(pkt stack.PacketBufferPtr) tcpip.Error { return &tcpip.ErrNotSupported{} } diff --git a/pkg/tap/switch.go b/pkg/tap/switch.go index 30766b734..654fd5ea9 100644 --- a/pkg/tap/switch.go +++ b/pkg/tap/switch.go @@ -19,13 +19,13 @@ import ( ) type VirtualDevice interface { - DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) + DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) LinkAddress() tcpip.LinkAddress IP() string } type NetworkSwitch interface { - DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) + DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) } type Switch struct { @@ -73,7 +73,7 @@ func (e *Switch) Connect(ep VirtualDevice) { e.gateway = ep } -func (e *Switch) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func (e *Switch) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { if err := e.tx(pkt); err != nil { log.Error(err) } @@ -111,24 +111,24 @@ func (e *Switch) connect(conn net.Conn) (int, bool) { return id, false } -func (e *Switch) tx(pkt *stack.PacketBuffer) error { +func (e *Switch) tx(pkt stack.PacketBufferPtr) error { if e.protocol.Stream() { return e.txStream(pkt, e.protocol.(streamProtocol)) } return e.txNonStream(pkt) } -func (e *Switch) txNonStream(pkt *stack.PacketBuffer) error { +func (e *Switch) txNonStream(pkt stack.PacketBufferPtr) error { return e.txBuf(pkt, nil) } -func (e *Switch) txStream(pkt *stack.PacketBuffer, sProtocol streamProtocol) error { +func (e *Switch) txStream(pkt stack.PacketBufferPtr, sProtocol streamProtocol) error { size := sProtocol.Buf() sProtocol.Write(size, pkt.Size()) return e.txBuf(pkt, size) } -func (e *Switch) txBuf(pkt *stack.PacketBuffer, size []byte) error { +func (e *Switch) txBuf(pkt stack.PacketBufferPtr, size []byte) error { e.writeLock.Lock() defer e.writeLock.Unlock() diff --git a/vendor/gvisor.dev/gvisor/pkg/atomicbitops/atomicbitops_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/atomicbitops/atomicbitops_state_autogen.go index 676d44439..903532331 100644 --- a/vendor/gvisor.dev/gvisor/pkg/atomicbitops/atomicbitops_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/atomicbitops/atomicbitops_state_autogen.go @@ -6,3 +6,36 @@ // +build !arm64 package atomicbitops + +import ( + "gvisor.dev/gvisor/pkg/state" +) + +func (b *Bool) StateTypeName() string { + return "pkg/atomicbitops.Bool" +} + +func (b *Bool) StateFields() []string { + return []string{ + "Uint32", + } +} + +func (b *Bool) beforeSave() {} + +// +checklocksignore +func (b *Bool) StateSave(stateSinkObject state.Sink) { + b.beforeSave() + stateSinkObject.Save(0, &b.Uint32) +} + +func (b *Bool) afterLoad() {} + +// +checklocksignore +func (b *Bool) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &b.Uint32) +} + +func init() { + state.Register((*Bool)(nil)) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/atomicbitops/bool.go b/vendor/gvisor.dev/gvisor/pkg/atomicbitops/bool.go new file mode 100644 index 000000000..60e646e8e --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/atomicbitops/bool.go @@ -0,0 +1,71 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package atomicbitops + +import "sync/atomic" + +// Bool is an atomic Boolean. +// +// It is implemented by a Uint32, with value 0 indicating false, and 1 +// indicating true. +// +// +stateify savable +type Bool struct { + Uint32 +} + +// FromBool returns an Bool initialized to value val. +// +//go:nosplit +func FromBool(val bool) Bool { + var u uint32 + if val { + u = 1 + } + return Bool{ + Uint32{ + value: u, + }, + } +} + +// Load is analogous to atomic.LoadBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Load() bool { + return atomic.LoadUint32(&b.value) == 1 +} + +// Store is analogous to atomic.StoreBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Store(val bool) { + var u uint32 + if val { + u = 1 + } + atomic.StoreUint32(&b.value, u) +} + +// Swap is analogous to atomic.SwapBool, if such a thing existed. +// +//go:nosplit +func (b *Bool) Swap(val bool) bool { + var u uint32 + if val { + u = 1 + } + return atomic.SwapUint32(&b.value, u) == 1 +} diff --git a/vendor/gvisor.dev/gvisor/pkg/bufferv2/buffer.go b/vendor/gvisor.dev/gvisor/pkg/bufferv2/buffer.go index 58e378907..a7459a376 100644 --- a/vendor/gvisor.dev/gvisor/pkg/bufferv2/buffer.go +++ b/vendor/gvisor.dev/gvisor/pkg/bufferv2/buffer.go @@ -20,6 +20,8 @@ package bufferv2 import ( "fmt" "io" + + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) // Buffer is a non-linear buffer. @@ -443,6 +445,24 @@ func (b *Buffer) SubApply(offset, length int, fn func(*View)) { } } +// Checksum calculates a checksum over the buffer's payload starting at offset. +func (b *Buffer) Checksum(offset int) uint16 { + if offset >= int(b.size) { + return 0 + } + var v *View + for v = b.data.Front(); v != nil && offset >= v.Size(); v = v.Next() { + offset -= v.Size() + } + + var cs checksum.Checksumer + cs.Add(v.AsSlice()[offset:]) + for v = v.Next(); v != nil; v = v.Next() { + cs.Add(v.AsSlice()) + } + return cs.Checksum() +} + // Merge merges the provided Buffer with this one. // // The other Buffer will be appended to v, and other will be empty after this diff --git a/vendor/gvisor.dev/gvisor/pkg/bufferv2/bufferv2_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/bufferv2/bufferv2_state_autogen.go index c30f6eda3..408c47699 100644 --- a/vendor/gvisor.dev/gvisor/pkg/bufferv2/bufferv2_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/bufferv2/bufferv2_state_autogen.go @@ -33,7 +33,7 @@ func (b *Buffer) afterLoad() {} // +checklocksignore func (b *Buffer) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &b.size) - stateSourceObject.LoadValue(0, new([]byte), func(y interface{}) { b.loadData(y.([]byte)) }) + stateSourceObject.LoadValue(0, new([]byte), func(y any) { b.loadData(y.([]byte)) }) } func (c *chunk) StateTypeName() string { diff --git a/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk.go b/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk.go index 4c62216ea..8a078acf5 100644 --- a/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk.go +++ b/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk.go @@ -21,12 +21,6 @@ import ( "gvisor.dev/gvisor/pkg/sync" ) -// PoolingEnabled is set to true when pooling is enabled. Added as a -// global to allow easy access. -// -// TODO(b/236996271): Remove once buffer pooling experiment complete. -var PoolingEnabled = true - const ( // This is log2(baseChunkSize). This number is used to calculate which pool // to use for a payload size by right shifting the payload size by this @@ -53,7 +47,7 @@ var chunkPools [numPools]sync.Pool func init() { for i := 0; i < numPools; i++ { chunkSize := baseChunkSize * (1 << i) - chunkPools[i].New = func() interface{} { + chunkPools[i].New = func() any { return &chunk{ data: make([]byte, chunkSize), } @@ -86,7 +80,7 @@ type chunk struct { func newChunk(size int) *chunk { var c *chunk - if !PoolingEnabled || size > MaxChunkSize { + if size > MaxChunkSize { c = &chunk{ data: make([]byte, size), } @@ -102,7 +96,7 @@ func newChunk(size int) *chunk { } func (c *chunk) destroy() { - if !PoolingEnabled || len(c.data) > MaxChunkSize { + if len(c.data) > MaxChunkSize { c.data = nil return } diff --git a/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk_refs.go b/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk_refs.go index d46f3898d..cf082532a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk_refs.go +++ b/vendor/gvisor.dev/gvisor/pkg/bufferv2/chunk_refs.go @@ -4,7 +4,7 @@ import ( "fmt" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/refsvfs2" + "gvisor.dev/gvisor/pkg/refs" ) // enableLogging indicates whether reference-related events should be logged (with @@ -44,20 +44,20 @@ type chunkRefs struct { // checking. func (r *chunkRefs) InitRefs() { r.refCount.Store(1) - refsvfs2.Register(r) + refs.Register(r) } -// RefType implements refsvfs2.CheckedObject.RefType. +// RefType implements refs.CheckedObject.RefType. func (r *chunkRefs) RefType() string { return fmt.Sprintf("%T", chunkobj)[1:] } -// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +// LeakMessage implements refs.CheckedObject.LeakMessage. func (r *chunkRefs) LeakMessage() string { return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) } -// LogRefs implements refsvfs2.CheckedObject.LogRefs. +// LogRefs implements refs.CheckedObject.LogRefs. func (r *chunkRefs) LogRefs() bool { return chunkenableLogging } @@ -74,7 +74,7 @@ func (r *chunkRefs) ReadRefs() int64 { func (r *chunkRefs) IncRef() { v := r.refCount.Add(1) if chunkenableLogging { - refsvfs2.LogIncRef(r, v) + refs.LogIncRef(r, v) } if v <= 1 { panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) @@ -98,7 +98,7 @@ func (r *chunkRefs) TryIncRef() bool { v := r.refCount.Add(-speculativeRef + 1) if chunkenableLogging { - refsvfs2.LogTryIncRef(r, v) + refs.LogTryIncRef(r, v) } return true } @@ -118,14 +118,14 @@ func (r *chunkRefs) TryIncRef() bool { func (r *chunkRefs) DecRef(destroy func()) { v := r.refCount.Add(-1) if chunkenableLogging { - refsvfs2.LogDecRef(r, v) + refs.LogDecRef(r, v) } switch { case v < 0: panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == 0: - refsvfs2.Unregister(r) + refs.Unregister(r) if destroy != nil { destroy() @@ -135,6 +135,6 @@ func (r *chunkRefs) DecRef(destroy func()) { func (r *chunkRefs) afterLoad() { if r.ReadRefs() > 0 { - refsvfs2.Register(r) + refs.Register(r) } } diff --git a/vendor/gvisor.dev/gvisor/pkg/bufferv2/view.go b/vendor/gvisor.dev/gvisor/pkg/bufferv2/view.go index 20811497f..8e45f220e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/bufferv2/view.go +++ b/vendor/gvisor.dev/gvisor/pkg/bufferv2/view.go @@ -26,7 +26,7 @@ import ( const ReadSize = 512 var viewPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &View{} }, } diff --git a/vendor/gvisor.dev/gvisor/pkg/context/context.go b/vendor/gvisor.dev/gvisor/pkg/context/context.go index c68a4ffc3..469e254ca 100644 --- a/vendor/gvisor.dev/gvisor/pkg/context/context.go +++ b/vendor/gvisor.dev/gvisor/pkg/context/context.go @@ -186,7 +186,7 @@ func Background() Context { // WithValue returns a copy of parent in which the value associated with key is // val. -func WithValue(parent Context, key, val interface{}) Context { +func WithValue(parent Context, key, val any) Context { return &withValue{ Context: parent, key: key, @@ -196,12 +196,12 @@ func WithValue(parent Context, key, val interface{}) Context { type withValue struct { Context - key interface{} - val interface{} + key any + val any } // Value implements Context.Value. -func (ctx *withValue) Value(key interface{}) interface{} { +func (ctx *withValue) Value(key any) any { if key == ctx.key { return ctx.val } diff --git a/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go b/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go index 6da806643..585a9a7d2 100644 --- a/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go +++ b/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid.go @@ -42,7 +42,7 @@ const ( // context represents context.Context. type context interface { - Value(key interface{}) interface{} + Value(key any) any } // FromContext returns the FeatureSet from the context, if available. diff --git a/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid_amd64_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid_amd64_state_autogen.go index 7186fd0fb..d97e11fa8 100644 --- a/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid_amd64_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/cpuid/cpuid_amd64_state_autogen.go @@ -33,7 +33,7 @@ func (fs *FeatureSet) afterLoad() {} // +checklocksignore func (fs *FeatureSet) StateLoad(stateSourceObject state.Source) { - stateSourceObject.LoadValue(0, new(Static), func(y interface{}) { fs.loadFunction(y.(Static)) }) + stateSourceObject.LoadValue(0, new(Static), func(y any) { fs.loadFunction(y.(Static)) }) } func (i *In) StateTypeName() string { diff --git a/vendor/gvisor.dev/gvisor/pkg/log/glog.go b/vendor/gvisor.dev/gvisor/pkg/log/glog.go index 47e22614b..553f7feb6 100644 --- a/vendor/gvisor.dev/gvisor/pkg/log/glog.go +++ b/vendor/gvisor.dev/gvisor/pkg/log/glog.go @@ -47,7 +47,7 @@ var pid = os.Getpid() // file The file name // line The line number // msg The user-supplied message -func (g GoogleEmitter) Emit(depth int, level Level, timestamp time.Time, format string, args ...interface{}) { +func (g GoogleEmitter) Emit(depth int, level Level, timestamp time.Time, format string, args ...any) { // Log level. prefix := byte('?') switch level { diff --git a/vendor/gvisor.dev/gvisor/pkg/log/json.go b/vendor/gvisor.dev/gvisor/pkg/log/json.go index 8c52dcc87..a7f55a9f9 100644 --- a/vendor/gvisor.dev/gvisor/pkg/log/json.go +++ b/vendor/gvisor.dev/gvisor/pkg/log/json.go @@ -62,7 +62,7 @@ type JSONEmitter struct { } // Emit implements Emitter.Emit. -func (e JSONEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...interface{}) { +func (e JSONEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...any) { j := jsonLog{ Msg: fmt.Sprintf(format, v...), Level: level, diff --git a/vendor/gvisor.dev/gvisor/pkg/log/json_k8s.go b/vendor/gvisor.dev/gvisor/pkg/log/json_k8s.go index 5883e95e1..0105c0682 100644 --- a/vendor/gvisor.dev/gvisor/pkg/log/json_k8s.go +++ b/vendor/gvisor.dev/gvisor/pkg/log/json_k8s.go @@ -33,7 +33,7 @@ type K8sJSONEmitter struct { } // Emit implements Emitter.Emit. -func (e K8sJSONEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...interface{}) { +func (e K8sJSONEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...any) { j := k8sJSONLog{ Log: fmt.Sprintf(format, v...), Level: level, diff --git a/vendor/gvisor.dev/gvisor/pkg/log/log.go b/vendor/gvisor.dev/gvisor/pkg/log/log.go index 7f8051e57..af95fb327 100644 --- a/vendor/gvisor.dev/gvisor/pkg/log/log.go +++ b/vendor/gvisor.dev/gvisor/pkg/log/log.go @@ -38,6 +38,7 @@ import ( "io" stdlog "log" "os" + "regexp" "runtime" "sync/atomic" "time" @@ -80,7 +81,7 @@ func (l Level) String() string { type Emitter interface { // Emit emits the given log statement. This allows for control over the // timestamp used for logging. - Emit(depth int, level Level, timestamp time.Time, format string, v ...interface{}) + Emit(depth int, level Level, timestamp time.Time, format string, v ...any) } // Writer writes the output to the given writer. @@ -144,7 +145,7 @@ func (l *Writer) Write(data []byte) (int, error) { } // Emit emits the message. -func (l *Writer) Emit(_ int, _ Level, _ time.Time, format string, args ...interface{}) { +func (l *Writer) Emit(_ int, _ Level, _ time.Time, format string, args ...any) { fmt.Fprintf(l, format, args...) } @@ -152,7 +153,7 @@ func (l *Writer) Emit(_ int, _ Level, _ time.Time, format string, args ...interf type MultiEmitter []Emitter // Emit emits to all emitters. -func (m *MultiEmitter) Emit(depth int, level Level, timestamp time.Time, format string, v ...interface{}) { +func (m *MultiEmitter) Emit(depth int, level Level, timestamp time.Time, format string, v ...any) { for _, e := range *m { e.Emit(1+depth, level, timestamp, format, v...) } @@ -160,7 +161,7 @@ func (m *MultiEmitter) Emit(depth int, level Level, timestamp time.Time, format // TestLogger is implemented by testing.T and testing.B. type TestLogger interface { - Logf(format string, v ...interface{}) + Logf(format string, v ...any) } // TestEmitter may be used for wrapping tests. @@ -169,7 +170,7 @@ type TestEmitter struct { } // Emit emits to the TestLogger. -func (t *TestEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...interface{}) { +func (t *TestEmitter) Emit(_ int, level Level, timestamp time.Time, format string, v ...any) { t.Logf(format, v...) } @@ -179,13 +180,13 @@ func (t *TestEmitter) Emit(_ int, level Level, timestamp time.Time, format strin // satisfies this interface, and may be passed around as a Logger. type Logger interface { // Debugf logs a debug statement. - Debugf(format string, v ...interface{}) + Debugf(format string, v ...any) // Infof logs at an info level. - Infof(format string, v ...interface{}) + Infof(format string, v ...any) // Warningf logs at a warning level. - Warningf(format string, v ...interface{}) + Warningf(format string, v ...any) // IsLogging returns true iff this level is being logged. This may be // used to short-circuit expensive operations for debugging calls. @@ -199,36 +200,36 @@ type BasicLogger struct { } // Debugf implements logger.Debugf. -func (l *BasicLogger) Debugf(format string, v ...interface{}) { +func (l *BasicLogger) Debugf(format string, v ...any) { l.DebugfAtDepth(1, format, v...) } // Infof implements logger.Infof. -func (l *BasicLogger) Infof(format string, v ...interface{}) { +func (l *BasicLogger) Infof(format string, v ...any) { l.InfofAtDepth(1, format, v...) } // Warningf implements logger.Warningf. -func (l *BasicLogger) Warningf(format string, v ...interface{}) { +func (l *BasicLogger) Warningf(format string, v ...any) { l.WarningfAtDepth(1, format, v...) } // DebugfAtDepth logs at a specific depth. -func (l *BasicLogger) DebugfAtDepth(depth int, format string, v ...interface{}) { +func (l *BasicLogger) DebugfAtDepth(depth int, format string, v ...any) { if l.IsLogging(Debug) { l.Emit(1+depth, Debug, time.Now(), format, v...) } } // InfofAtDepth logs at a specific depth. -func (l *BasicLogger) InfofAtDepth(depth int, format string, v ...interface{}) { +func (l *BasicLogger) InfofAtDepth(depth int, format string, v ...any) { if l.IsLogging(Info) { l.Emit(1+depth, Info, time.Now(), format, v...) } } // WarningfAtDepth logs at a specific depth. -func (l *BasicLogger) WarningfAtDepth(depth int, format string, v ...interface{}) { +func (l *BasicLogger) WarningfAtDepth(depth int, format string, v ...any) { if l.IsLogging(Warning) { l.Emit(1+depth, Warning, time.Now(), format, v...) } @@ -275,32 +276,32 @@ func SetLevel(newLevel Level) { } // Debugf logs to the global logger. -func Debugf(format string, v ...interface{}) { +func Debugf(format string, v ...any) { Log().DebugfAtDepth(1, format, v...) } // Infof logs to the global logger. -func Infof(format string, v ...interface{}) { +func Infof(format string, v ...any) { Log().InfofAtDepth(1, format, v...) } // Warningf logs to the global logger. -func Warningf(format string, v ...interface{}) { +func Warningf(format string, v ...any) { Log().WarningfAtDepth(1, format, v...) } // DebugfAtDepth logs to the global logger. -func DebugfAtDepth(depth int, format string, v ...interface{}) { +func DebugfAtDepth(depth int, format string, v ...any) { Log().DebugfAtDepth(1+depth, format, v...) } // InfofAtDepth logs to the global logger. -func InfofAtDepth(depth int, format string, v ...interface{}) { +func InfofAtDepth(depth int, format string, v ...any) { Log().InfofAtDepth(1+depth, format, v...) } // WarningfAtDepth logs to the global logger. -func WarningfAtDepth(depth int, format string, v ...interface{}) { +func WarningfAtDepth(depth int, format string, v ...any) { Log().WarningfAtDepth(1+depth, format, v...) } @@ -325,11 +326,27 @@ func Stacks(all bool) []byte { return trace } +// stackRegexp matches one level within a stack trace. +var stackRegexp = regexp.MustCompile("(?m)^\\S+\\(.*\\)$\\r?\\n^\\t\\S+:\\d+.*$\\r?\\n") + +// LocalStack returns the local goroutine stack, excluding the top N entries. +// LocalStack's own entry is excluded by default and does not need to be counted in excludeTopN. +func LocalStack(excludeTopN int) []byte { + replaceNext := excludeTopN + 1 + return stackRegexp.ReplaceAllFunc(Stacks(false), func(s []byte) []byte { + if replaceNext > 0 { + replaceNext-- + return nil + } + return s + }) +} + // Traceback logs the given message and dumps a stacktrace of the current // goroutine. // // This will be print a traceback, tb, as Warningf(format+":\n%s", v..., tb). -func Traceback(format string, v ...interface{}) { +func Traceback(format string, v ...any) { v = append(v, Stacks(false)) Warningf(format+":\n%s", v...) } @@ -337,7 +354,7 @@ func Traceback(format string, v ...interface{}) { // TracebackAll logs the given message and dumps a stacktrace of all goroutines. // // This will be print a traceback, tb, as Warningf(format+":\n%s", v..., tb). -func TracebackAll(format string, v ...interface{}) { +func TracebackAll(format string, v ...any) { v = append(v, Stacks(true)) Warningf(format+":\n%s", v...) } @@ -350,7 +367,7 @@ func IsLogging(level Level) bool { // CopyStandardLogTo redirects the stdlib log package global output to the global // logger for the specified level. func CopyStandardLogTo(l Level) error { - var f func(string, ...interface{}) + var f func(string, ...any) switch l { case Debug: diff --git a/vendor/gvisor.dev/gvisor/pkg/log/rate_limited.go b/vendor/gvisor.dev/gvisor/pkg/log/rate_limited.go index 285d9b26d..e274238dc 100644 --- a/vendor/gvisor.dev/gvisor/pkg/log/rate_limited.go +++ b/vendor/gvisor.dev/gvisor/pkg/log/rate_limited.go @@ -25,19 +25,19 @@ type rateLimitedLogger struct { limit *rate.Limiter } -func (rl *rateLimitedLogger) Debugf(format string, v ...interface{}) { +func (rl *rateLimitedLogger) Debugf(format string, v ...any) { if rl.limit.Allow() { rl.logger.Debugf(format, v...) } } -func (rl *rateLimitedLogger) Infof(format string, v ...interface{}) { +func (rl *rateLimitedLogger) Infof(format string, v ...any) { if rl.limit.Allow() { rl.logger.Infof(format, v...) } } -func (rl *rateLimitedLogger) Warningf(format string, v ...interface{}) { +func (rl *rateLimitedLogger) Warningf(format string, v ...any) { if rl.limit.Allow() { rl.logger.Warningf(format, v...) } diff --git a/vendor/gvisor.dev/gvisor/pkg/refs/refcounter.go b/vendor/gvisor.dev/gvisor/pkg/refs/refcounter.go index a15b218fb..ec60ee1a0 100644 --- a/vendor/gvisor.dev/gvisor/pkg/refs/refcounter.go +++ b/vendor/gvisor.dev/gvisor/pkg/refs/refcounter.go @@ -12,234 +12,52 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package refs defines an interface for reference counted objects. It -// also provides a drop-in implementation called AtomicRefCount. +// Package refs defines an interface for reference counted objects. package refs import ( "bytes" "fmt" - "reflect" "runtime" - "sync/atomic" "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/context" - "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sync" ) // RefCounter is the interface to be implemented by objects that are reference // counted. -// -// TODO(gvisor.dev/issue/1624): Get rid of most of this package and replace it -// with refsvfs2. type RefCounter interface { // IncRef increments the reference counter on the object. IncRef() - // DecRef decrements the reference counter on the object. - // - // Note that AtomicRefCounter.DecRef() does not support destructors. - // If a type has a destructor, it must implement its own DecRef() - // method and call AtomicRefCounter.DecRefWithDestructor(destructor). + // DecRef decrements the object's reference count. Users of refs_template.Refs + // may specify a destructor to be called once the reference count reaches zero. DecRef(ctx context.Context) - - // TryIncRef attempts to increase the reference counter on the object, - // but may fail if all references have already been dropped. This - // should be used only in special circumstances, such as WeakRefs. - TryIncRef() bool - - // addWeakRef adds the given weak reference. Note that you should have a - // reference to the object when calling this method. - addWeakRef(*WeakRef) - - // dropWeakRef drops the given weak reference. Note that you should have - // a reference to the object when calling this method. - dropWeakRef(*WeakRef) -} - -// A WeakRefUser is notified when the last non-weak reference is dropped. -type WeakRefUser interface { - // WeakRefGone is called when the last non-weak reference is dropped. - WeakRefGone(ctx context.Context) -} - -// WeakRef is a weak reference. -// -// +stateify savable -type WeakRef struct { - weakRefEntry `state:"nosave"` - - // obj is an atomic value that points to the refCounter. - obj atomic.Value `state:".(savedReference)"` - - // user is notified when the weak ref is zapped by the object getting - // destroyed. - user WeakRefUser -} - -// weakRefPool is a pool of weak references to avoid allocations on the hot path. -var weakRefPool = sync.Pool{ - New: func() interface{} { - return &WeakRef{} - }, -} - -// NewWeakRef acquires a weak reference for the given object. -// -// An optional user will be notified when the last non-weak reference is -// dropped. -// -// Note that you must hold a reference to the object prior to getting a weak -// reference. (But you may drop the non-weak reference after that.) -func NewWeakRef(rc RefCounter, u WeakRefUser) *WeakRef { - w := weakRefPool.Get().(*WeakRef) - w.init(rc, u) - return w -} - -// get attempts to get a normal reference to the underlying object, and returns -// the object. If this weak reference has already been zapped (the object has -// been destroyed) then false is returned. If the object still exists, then -// true is returned. -func (w *WeakRef) get() (RefCounter, bool) { - rc := w.obj.Load().(RefCounter) - if v := reflect.ValueOf(rc); v == reflect.Zero(v.Type()) { - // This pointer has already been zapped by zap() below. We do - // this to ensure that the GC can collect the underlying - // RefCounter objects and they don't hog resources. - return nil, false - } - if !rc.TryIncRef() { - return nil, true - } - return rc, true -} - -// Get attempts to get a normal reference to the underlying object, and returns -// the object. If this fails (the object no longer exists), then nil will be -// returned instead. -func (w *WeakRef) Get() RefCounter { - rc, _ := w.get() - return rc -} - -// Drop drops this weak reference. You should always call drop when you are -// finished with the weak reference. You may not use this object after calling -// drop. -func (w *WeakRef) Drop(ctx context.Context) { - rc, ok := w.get() - if !ok { - // We've been zapped already. When the refcounter has called - // zap, we're guaranteed it's not holding references. - weakRefPool.Put(w) - return - } - if rc == nil { - // The object is in the process of being destroyed. We can't - // remove this from the object's list, nor can we return this - // object to the pool. It'll just be garbage collected. This is - // a rare edge case, so it's not a big deal. - return - } - - // At this point, we have a reference on the object. So destruction - // of the object (and zapping this weak reference) can't race here. - rc.dropWeakRef(w) - - // And now aren't on the object's list of weak references. So it won't - // zap us if this causes the reference count to drop to zero. - rc.DecRef(ctx) - - // Return to the pool. - weakRefPool.Put(w) } -// init initializes this weak reference. -func (w *WeakRef) init(rc RefCounter, u WeakRefUser) { - // Reset the contents of the weak reference. - // This is important because we are reseting the atomic value type. - // Otherwise, we could panic here if obj is different than what it was - // the last time this was used. - *w = WeakRef{} - w.user = u - w.obj.Store(rc) - - // In the load path, we may already have a nil value. So we need to - // check whether or not that is the case before calling addWeakRef. - if v := reflect.ValueOf(rc); v != reflect.Zero(v.Type()) { - rc.addWeakRef(w) - } -} +// TryRefCounter is like RefCounter but allow the ref increment to be tried. +type TryRefCounter interface { + RefCounter -// zap zaps this weak reference. -func (w *WeakRef) zap() { - // We need to be careful about types here. - // So reflect is involved. But it's not that bad. - rc := w.obj.Load() - typ := reflect.TypeOf(rc) - w.obj.Store(reflect.Zero(typ).Interface()) -} - -// AtomicRefCount keeps a reference count using atomic operations and calls the -// destructor when the count reaches zero. -// -// Do not use AtomicRefCount for new ref-counted objects! It is deprecated in -// favor of the refsvfs2 package. -// -// N.B. To allow the zero-object to be initialized, the count is offset by -// 1, that is, when refCount is n, there are really n+1 references. -// -// +stateify savable -type AtomicRefCount struct { - // refCount is composed of two fields: - // - // [32-bit speculative references]:[32-bit real references] - // - // Speculative references are used for TryIncRef, to avoid a - // CompareAndSwap loop. See IncRef, DecRef and TryIncRef for details of - // how these fields are used. - refCount atomicbitops.Int64 - - // name is the name of the type which owns this ref count. - // - // name is immutable after EnableLeakCheck is called. - name string - - // stack optionally records the caller of EnableLeakCheck. - // - // stack is immutable after EnableLeakCheck is called. - stack []uintptr - - // mu protects the list below. - mu sync.Mutex `state:"nosave"` - - // weakRefs is our collection of weak references. - weakRefs weakRefList `state:"nosave"` + // TryIncRef attempts to increment the reference count, but may fail if all + // references have already been dropped, in which case it returns false. If + // true is returned, then a valid reference is now held on the object. + TryIncRef() bool } // LeakMode configures the leak checker. type LeakMode uint32 -// TODO(gvisor.dev/issue/1624): Simplify down to two modes (on/off) once vfs1 -// ref counting is gone. const ( - // UninitializedLeakChecking indicates that the leak checker has not yet been initialized. - UninitializedLeakChecking LeakMode = iota - // NoLeakChecking indicates that no effort should be made to check for // leaks. - NoLeakChecking + NoLeakChecking LeakMode = iota // LeaksLogWarning indicates that a warning should be logged when leaks // are found. LeaksLogWarning - // LeaksLogTraces indicates that a trace collected during allocation - // should be logged when leaks are found. - LeaksLogTraces - // LeaksPanic indidcates that a panic should be issued when leaks are found. LeaksPanic ) @@ -251,8 +69,6 @@ func (l *LeakMode) Set(v string) error { *l = NoLeakChecking case "log-names": *l = LeaksLogWarning - case "log-traces": - *l = LeaksLogTraces case "panic": *l = LeaksPanic default: @@ -262,21 +78,17 @@ func (l *LeakMode) Set(v string) error { } // Get implements flag.Value. -func (l *LeakMode) Get() interface{} { +func (l *LeakMode) Get() any { return *l } // String implements flag.Value. func (l LeakMode) String() string { switch l { - case UninitializedLeakChecking: - return "uninitialized" case NoLeakChecking: return "disabled" case LeaksLogWarning: return "log-names" - case LeaksLogTraces: - return "log-traces" case LeaksPanic: return "panic" default: @@ -373,161 +185,6 @@ func FormatStack(pcs []uintptr) string { return trace.String() } -func (r *AtomicRefCount) finalize() { - var note string - switch LeakMode(leakMode.Load()) { - case NoLeakChecking: - return - case UninitializedLeakChecking: - note = "(Leak checker uninitialized): " - } - if n := r.ReadRefs(); n != 0 { - msg := fmt.Sprintf("%sAtomicRefCount %p owned by %q garbage collected with ref count of %d (want 0)", note, r, r.name, n) - if len(r.stack) != 0 { - msg += ":\nCaller:\n" + FormatStack(r.stack) - } else { - msg += " (enable trace logging to debug)" - } - log.Warningf(msg) - } -} - -// EnableLeakCheck checks for reference leaks when the AtomicRefCount gets -// garbage collected. -// -// This function adds a finalizer to the AtomicRefCount, so the AtomicRefCount -// must be at the beginning of its parent. -// -// name is a friendly name that will be listed as the owner of the -// AtomicRefCount in logs. It should be the name of the parent type, including -// package. -func (r *AtomicRefCount) EnableLeakCheck(name string) { - if name == "" { - panic("invalid name") - } - switch LeakMode(leakMode.Load()) { - case NoLeakChecking: - return - case LeaksLogTraces: - r.stack = RecordStack() - } - r.name = name - runtime.SetFinalizer(r, (*AtomicRefCount).finalize) -} - -// ReadRefs returns the current number of references. The returned count is -// inherently racy and is unsafe to use without external synchronization. -func (r *AtomicRefCount) ReadRefs() int64 { - // Account for the internal -1 offset on refcounts. - return r.refCount.Load() + 1 -} - -// IncRef increments this object's reference count. While the count is kept -// greater than zero, the destructor doesn't get called. -// -// The sanity check here is limited to real references, since if they have -// dropped beneath zero then the object should have been destroyed. -// -//go:nosplit -func (r *AtomicRefCount) IncRef() { - if v := r.refCount.Add(1); v <= 0 { - panic("Incrementing non-positive ref count") - } -} - -// TryIncRef attempts to increment the reference count, *unless the count has -// already reached zero*. If false is returned, then the object has already -// been destroyed, and the weak reference is no longer valid. If true if -// returned then a valid reference is now held on the object. -// -// To do this safely without a loop, a speculative reference is first acquired -// on the object. This allows multiple concurrent TryIncRef calls to -// distinguish other TryIncRef calls from genuine references held. -// -//go:nosplit -func (r *AtomicRefCount) TryIncRef() bool { - const speculativeRef = 1 << 32 - v := r.refCount.Add(speculativeRef) - if int32(v) < 0 { - // This object has already been freed. - r.refCount.Add(-speculativeRef) - return false - } - - // Turn into a real reference. - r.refCount.Add(-speculativeRef + 1) - return true -} - -// addWeakRef adds the given weak reference. -func (r *AtomicRefCount) addWeakRef(w *WeakRef) { - r.mu.Lock() - r.weakRefs.PushBack(w) - r.mu.Unlock() -} - -// dropWeakRef drops the given weak reference. -func (r *AtomicRefCount) dropWeakRef(w *WeakRef) { - r.mu.Lock() - r.weakRefs.Remove(w) - r.mu.Unlock() -} - -// DecRefWithDestructor decrements the object's reference count. If the -// resulting count is negative and the destructor is not nil, then the -// destructor will be called. -// -// Note that speculative references are counted here. Since they were added -// prior to real references reaching zero, they will successfully convert to -// real references. In other words, we see speculative references only in the -// following case: -// -// A: TryIncRef [speculative increase => sees non-negative references] -// B: DecRef [real decrease] -// A: TryIncRef [transform speculative to real] -// -//go:nosplit -func (r *AtomicRefCount) DecRefWithDestructor(ctx context.Context, destroy func(context.Context)) { - switch v := r.refCount.Add(-1); { - case v < -1: - panic("Decrementing non-positive ref count") - - case v == -1: - // Zap weak references. Note that at this point, all weak - // references are already invalid. That is, TryIncRef() will - // return false due to the reference count check. - r.mu.Lock() - for !r.weakRefs.Empty() { - w := r.weakRefs.Front() - // Capture the callback because w cannot be touched - // after it's zapped -- the owner is free it reuse it - // after that. - user := w.user - r.weakRefs.Remove(w) - w.zap() - - if user != nil { - r.mu.Unlock() - user.WeakRefGone(ctx) - r.mu.Lock() - } - } - r.mu.Unlock() - - // Call the destructor. - if destroy != nil { - destroy(ctx) - } - } -} - -// DecRef decrements this object's reference count. -// -//go:nosplit -func (r *AtomicRefCount) DecRef(ctx context.Context) { - r.DecRefWithDestructor(ctx, nil) -} - // OnExit is called on sandbox exit. It runs GC to enqueue refcount finalizers, // which check for reference leaks. There is no way to guarantee that every // finalizer will run before exiting, but this at least ensures that they will diff --git a/vendor/gvisor.dev/gvisor/pkg/refs/refcounter_state.go b/vendor/gvisor.dev/gvisor/pkg/refs/refcounter_state.go deleted file mode 100644 index 7c99fd2b5..000000000 --- a/vendor/gvisor.dev/gvisor/pkg/refs/refcounter_state.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package refs - -// +stateify savable -type savedReference struct { - obj interface{} -} - -func (w *WeakRef) saveObj() savedReference { - // We load the object directly, because it is typed. This will be - // serialized and loaded as a typed value. - return savedReference{w.obj.Load()} -} - -func (w *WeakRef) loadObj(v savedReference) { - // See note above. This will be serialized and loaded typed. So we're okay - // as long as refs aren't changing during save and load (which they should - // not be). - // - // w.user is loaded before loadObj is called. - w.init(v.obj.(RefCounter), w.user) -} diff --git a/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs_map.go b/vendor/gvisor.dev/gvisor/pkg/refs/refs_map.go similarity index 88% rename from vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs_map.go rename to vendor/gvisor.dev/gvisor/pkg/refs/refs_map.go index 49605349e..f94fea87c 100644 --- a/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs_map.go +++ b/vendor/gvisor.dev/gvisor/pkg/refs/refs_map.go @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package refsvfs2 +package refs import ( "fmt" "gvisor.dev/gvisor/pkg/log" - refs_vfs1 "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/sync" ) @@ -50,14 +49,14 @@ func init() { // LeakCheckEnabled returns whether leak checking is enabled. The following // functions should only be called if it returns true. func LeakCheckEnabled() bool { - mode := refs_vfs1.GetLeakMode() - return mode != refs_vfs1.NoLeakChecking && mode != refs_vfs1.UninitializedLeakChecking + mode := GetLeakMode() + return mode != NoLeakChecking } // leakCheckPanicEnabled returns whether DoLeakCheck() should panic when leaks // are detected. func leakCheckPanicEnabled() bool { - return refs_vfs1.GetLeakMode() == refs_vfs1.LeaksPanic + return GetLeakMode() == LeaksPanic } // Register adds obj to the live object map. @@ -116,7 +115,7 @@ func LogDecRef(obj CheckedObject, refs int64) { // obj.LogRefs() should be checked before calling logEvent, in order to avoid // calling any text processing needed to evaluate msg. func logEvent(obj CheckedObject, msg string) { - log.Infof("[%s %p] %s:\n%s", obj.RefType(), obj, msg, refs_vfs1.FormatStack(refs_vfs1.RecordStack())) + log.Infof("[%s %p] %s:\n%s", obj.RefType(), obj, msg, FormatStack(RecordStack())) } // checkOnce makes sure that leak checking is only done once. DoLeakCheck is @@ -142,14 +141,35 @@ func DoRepeatedLeakCheck() { } } +type leakCheckDisabled interface { + LeakCheckDisabled() bool +} + +// CleanupSync is used to wait for async cleanup actions. +var CleanupSync sync.WaitGroup + func doLeakCheck() { + CleanupSync.Wait() liveObjectsMu.Lock() defer liveObjectsMu.Unlock() leaked := len(liveObjects) if leaked > 0 { + n := 0 msg := fmt.Sprintf("Leak checking detected %d leaked objects:\n", leaked) for obj := range liveObjects { + skip := false + if o, ok := obj.(leakCheckDisabled); ok { + skip = o.LeakCheckDisabled() + } + if skip { + log.Debugf(obj.LeakMessage()) + continue + } msg += obj.LeakMessage() + "\n" + n++ + } + if n == 0 { + return } if leakCheckPanicEnabled() { panic(msg) diff --git a/vendor/gvisor.dev/gvisor/pkg/refs/refs_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/refs/refs_state_autogen.go index 86a102119..dfa2c1bb3 100644 --- a/vendor/gvisor.dev/gvisor/pkg/refs/refs_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/refs/refs_state_autogen.go @@ -1,157 +1,3 @@ // automatically generated by stateify. package refs - -import ( - "gvisor.dev/gvisor/pkg/state" -) - -func (w *WeakRef) StateTypeName() string { - return "pkg/refs.WeakRef" -} - -func (w *WeakRef) StateFields() []string { - return []string{ - "obj", - "user", - } -} - -func (w *WeakRef) beforeSave() {} - -// +checklocksignore -func (w *WeakRef) StateSave(stateSinkObject state.Sink) { - w.beforeSave() - var objValue savedReference - objValue = w.saveObj() - stateSinkObject.SaveValue(0, objValue) - stateSinkObject.Save(1, &w.user) -} - -func (w *WeakRef) afterLoad() {} - -// +checklocksignore -func (w *WeakRef) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(1, &w.user) - stateSourceObject.LoadValue(0, new(savedReference), func(y interface{}) { w.loadObj(y.(savedReference)) }) -} - -func (r *AtomicRefCount) StateTypeName() string { - return "pkg/refs.AtomicRefCount" -} - -func (r *AtomicRefCount) StateFields() []string { - return []string{ - "refCount", - "name", - "stack", - } -} - -func (r *AtomicRefCount) beforeSave() {} - -// +checklocksignore -func (r *AtomicRefCount) StateSave(stateSinkObject state.Sink) { - r.beforeSave() - stateSinkObject.Save(0, &r.refCount) - stateSinkObject.Save(1, &r.name) - stateSinkObject.Save(2, &r.stack) -} - -func (r *AtomicRefCount) afterLoad() {} - -// +checklocksignore -func (r *AtomicRefCount) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &r.refCount) - stateSourceObject.Load(1, &r.name) - stateSourceObject.Load(2, &r.stack) -} - -func (s *savedReference) StateTypeName() string { - return "pkg/refs.savedReference" -} - -func (s *savedReference) StateFields() []string { - return []string{ - "obj", - } -} - -func (s *savedReference) beforeSave() {} - -// +checklocksignore -func (s *savedReference) StateSave(stateSinkObject state.Sink) { - s.beforeSave() - stateSinkObject.Save(0, &s.obj) -} - -func (s *savedReference) afterLoad() {} - -// +checklocksignore -func (s *savedReference) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &s.obj) -} - -func (l *weakRefList) StateTypeName() string { - return "pkg/refs.weakRefList" -} - -func (l *weakRefList) StateFields() []string { - return []string{ - "head", - "tail", - } -} - -func (l *weakRefList) beforeSave() {} - -// +checklocksignore -func (l *weakRefList) StateSave(stateSinkObject state.Sink) { - l.beforeSave() - stateSinkObject.Save(0, &l.head) - stateSinkObject.Save(1, &l.tail) -} - -func (l *weakRefList) afterLoad() {} - -// +checklocksignore -func (l *weakRefList) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &l.head) - stateSourceObject.Load(1, &l.tail) -} - -func (e *weakRefEntry) StateTypeName() string { - return "pkg/refs.weakRefEntry" -} - -func (e *weakRefEntry) StateFields() []string { - return []string{ - "next", - "prev", - } -} - -func (e *weakRefEntry) beforeSave() {} - -// +checklocksignore -func (e *weakRefEntry) StateSave(stateSinkObject state.Sink) { - e.beforeSave() - stateSinkObject.Save(0, &e.next) - stateSinkObject.Save(1, &e.prev) -} - -func (e *weakRefEntry) afterLoad() {} - -// +checklocksignore -func (e *weakRefEntry) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &e.next) - stateSourceObject.Load(1, &e.prev) -} - -func init() { - state.Register((*WeakRef)(nil)) - state.Register((*AtomicRefCount)(nil)) - state.Register((*savedReference)(nil)) - state.Register((*weakRefList)(nil)) - state.Register((*weakRefEntry)(nil)) -} diff --git a/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs.go b/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs.go deleted file mode 100644 index fe3e4a1ca..000000000 --- a/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refs.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package refsvfs2 defines an interface for a reference-counted object. -package refsvfs2 - -import ( - "gvisor.dev/gvisor/pkg/context" -) - -// RefCounter is the interface to be implemented by objects that are reference -// counted. -type RefCounter interface { - // IncRef increments the reference counter on the object. - IncRef() - - // DecRef decrements the object's reference count. Users of refs_template.Refs - // may specify a destructor to be called once the reference count reaches zero. - DecRef(ctx context.Context) -} - -// TryRefCounter is like RefCounter but allow the ref increment to be tried. -type TryRefCounter interface { - RefCounter - - // TryIncRef attempts to increment the reference count, but may fail if all - // references have already been dropped, in which case it returns false. If - // true is returned, then a valid reference is now held on the object. - TryIncRef() bool -} diff --git a/vendor/gvisor.dev/gvisor/pkg/sleep/sleep_unsafe_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/sleep/sleep_unsafe_state_autogen.go index 2eaef1ff3..d91ace020 100644 --- a/vendor/gvisor.dev/gvisor/pkg/sleep/sleep_unsafe_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/sleep/sleep_unsafe_state_autogen.go @@ -36,7 +36,7 @@ func (s *Sleeper) afterLoad() {} func (s *Sleeper) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &s.localList) stateSourceObject.Load(2, &s.allWakers) - stateSourceObject.LoadValue(0, new(*Waker), func(y interface{}) { s.loadSharedList(y.(*Waker)) }) + stateSourceObject.LoadValue(0, new(*Waker), func(y any) { s.loadSharedList(y.(*Waker)) }) } func (w *Waker) StateTypeName() string { @@ -69,7 +69,7 @@ func (w *Waker) afterLoad() {} func (w *Waker) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &w.next) stateSourceObject.Load(2, &w.allWakersNext) - stateSourceObject.LoadValue(0, new(wakerState), func(y interface{}) { w.loadS(y.(wakerState)) }) + stateSourceObject.LoadValue(0, new(wakerState), func(y any) { w.loadS(y.(wakerState)) }) } func init() { diff --git a/vendor/gvisor.dev/gvisor/pkg/state/deferred_list.go b/vendor/gvisor.dev/gvisor/pkg/state/deferred_list.go index 08fd1b990..a18b8bc2f 100644 --- a/vendor/gvisor.dev/gvisor/pkg/state/deferred_list.go +++ b/vendor/gvisor.dev/gvisor/pkg/state/deferred_list.go @@ -1,5 +1,20 @@ package state +// ElementMapper provides an identity mapping by default. +// +// This can be replaced to provide a struct that maps elements to linker +// objects, if they are not the same. An ElementMapper is not typically +// required if: Linker is left as is, Element is left as is, or Linker and +// Element are the same type. +type deferredElementMapper struct{} + +// linkerFor maps an Element to a Linker. +// +// This default implementation should be inlined. +// +//go:nosplit +func (deferredElementMapper) linkerFor(elem *objectEncodeState) *objectEncodeState { return elem } + // List is an intrusive list. Entries can be added to or removed from the list // in O(1) time and with no additional memory allocations. // @@ -50,7 +65,7 @@ func (l *deferredList) Back() *objectEncodeState { // //go:nosplit func (l *deferredList) Len() (count int) { - for e := l.Front(); e != nil; e = (deferredMapper{}.linkerFor(e)).Next() { + for e := l.Front(); e != nil; e = (deferredElementMapper{}.linkerFor(e)).Next() { count++ } return count @@ -60,11 +75,11 @@ func (l *deferredList) Len() (count int) { // //go:nosplit func (l *deferredList) PushFront(e *objectEncodeState) { - linker := deferredMapper{}.linkerFor(e) + linker := deferredElementMapper{}.linkerFor(e) linker.SetNext(l.head) linker.SetPrev(nil) if l.head != nil { - deferredMapper{}.linkerFor(l.head).SetPrev(e) + deferredElementMapper{}.linkerFor(l.head).SetPrev(e) } else { l.tail = e } @@ -80,8 +95,8 @@ func (l *deferredList) PushFrontList(m *deferredList) { l.head = m.head l.tail = m.tail } else if m.head != nil { - deferredMapper{}.linkerFor(l.head).SetPrev(m.tail) - deferredMapper{}.linkerFor(m.tail).SetNext(l.head) + deferredElementMapper{}.linkerFor(l.head).SetPrev(m.tail) + deferredElementMapper{}.linkerFor(m.tail).SetNext(l.head) l.head = m.head } @@ -93,11 +108,11 @@ func (l *deferredList) PushFrontList(m *deferredList) { // //go:nosplit func (l *deferredList) PushBack(e *objectEncodeState) { - linker := deferredMapper{}.linkerFor(e) + linker := deferredElementMapper{}.linkerFor(e) linker.SetNext(nil) linker.SetPrev(l.tail) if l.tail != nil { - deferredMapper{}.linkerFor(l.tail).SetNext(e) + deferredElementMapper{}.linkerFor(l.tail).SetNext(e) } else { l.head = e } @@ -113,8 +128,8 @@ func (l *deferredList) PushBackList(m *deferredList) { l.head = m.head l.tail = m.tail } else if m.head != nil { - deferredMapper{}.linkerFor(l.tail).SetNext(m.head) - deferredMapper{}.linkerFor(m.head).SetPrev(l.tail) + deferredElementMapper{}.linkerFor(l.tail).SetNext(m.head) + deferredElementMapper{}.linkerFor(m.head).SetPrev(l.tail) l.tail = m.tail } @@ -126,8 +141,8 @@ func (l *deferredList) PushBackList(m *deferredList) { // //go:nosplit func (l *deferredList) InsertAfter(b, e *objectEncodeState) { - bLinker := deferredMapper{}.linkerFor(b) - eLinker := deferredMapper{}.linkerFor(e) + bLinker := deferredElementMapper{}.linkerFor(b) + eLinker := deferredElementMapper{}.linkerFor(e) a := bLinker.Next() @@ -136,7 +151,7 @@ func (l *deferredList) InsertAfter(b, e *objectEncodeState) { bLinker.SetNext(e) if a != nil { - deferredMapper{}.linkerFor(a).SetPrev(e) + deferredElementMapper{}.linkerFor(a).SetPrev(e) } else { l.tail = e } @@ -146,8 +161,8 @@ func (l *deferredList) InsertAfter(b, e *objectEncodeState) { // //go:nosplit func (l *deferredList) InsertBefore(a, e *objectEncodeState) { - aLinker := deferredMapper{}.linkerFor(a) - eLinker := deferredMapper{}.linkerFor(e) + aLinker := deferredElementMapper{}.linkerFor(a) + eLinker := deferredElementMapper{}.linkerFor(e) b := aLinker.Prev() eLinker.SetNext(a) @@ -155,7 +170,7 @@ func (l *deferredList) InsertBefore(a, e *objectEncodeState) { aLinker.SetPrev(e) if b != nil { - deferredMapper{}.linkerFor(b).SetNext(e) + deferredElementMapper{}.linkerFor(b).SetNext(e) } else { l.head = e } @@ -165,18 +180,18 @@ func (l *deferredList) InsertBefore(a, e *objectEncodeState) { // //go:nosplit func (l *deferredList) Remove(e *objectEncodeState) { - linker := deferredMapper{}.linkerFor(e) + linker := deferredElementMapper{}.linkerFor(e) prev := linker.Prev() next := linker.Next() if prev != nil { - deferredMapper{}.linkerFor(prev).SetNext(next) + deferredElementMapper{}.linkerFor(prev).SetNext(next) } else if l.head == e { l.head = next } if next != nil { - deferredMapper{}.linkerFor(next).SetPrev(prev) + deferredElementMapper{}.linkerFor(next).SetPrev(prev) } else if l.tail == e { l.tail = prev } diff --git a/vendor/gvisor.dev/gvisor/pkg/state/encode.go b/vendor/gvisor.dev/gvisor/pkg/state/encode.go index 157ac0dd2..9f15c3c2e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/state/encode.go +++ b/vendor/gvisor.dev/gvisor/pkg/state/encode.go @@ -839,11 +839,6 @@ func WriteHeader(w wire.Writer, length uint64, object bool) error { }) } -// deferredMapper is for the deferred list. -type deferredMapper struct{} - -func (deferredMapper) linkerFor(oes *objectEncodeState) *deferredEntry { return &oes.deferredEntry } - // addrSetFunctions is used by addrSet. type addrSetFunctions struct{} diff --git a/vendor/gvisor.dev/gvisor/pkg/state/state.go b/vendor/gvisor.dev/gvisor/pkg/state/state.go index ff4b30c36..4a9e6eadf 100644 --- a/vendor/gvisor.dev/gvisor/pkg/state/state.go +++ b/vendor/gvisor.dev/gvisor/pkg/state/state.go @@ -87,7 +87,7 @@ func (e *ErrState) Unwrap() error { } // Save saves the given object state. -func Save(ctx context.Context, w wire.Writer, rootPtr interface{}) (Stats, error) { +func Save(ctx context.Context, w wire.Writer, rootPtr any) (Stats, error) { // Create the encoding state. es := encodeState{ ctx: ctx, @@ -106,7 +106,7 @@ func Save(ctx context.Context, w wire.Writer, rootPtr interface{}) (Stats, error } // Load loads a checkpoint. -func Load(ctx context.Context, r wire.Reader, rootPtr interface{}) (Stats, error) { +func Load(ctx context.Context, r wire.Reader, rootPtr any) (Stats, error) { // Create the decoding state. ds := decodeState{ ctx: ctx, @@ -155,7 +155,7 @@ type Sink struct { // m.Load(0, &x.A) // Field is A. // m.Load(1, &x.B) // Field is B. // } -func (s Sink) Save(slot int, objPtr interface{}) { +func (s Sink) Save(slot int, objPtr any) { s.internal.save(slot, reflect.ValueOf(objPtr).Elem()) } @@ -171,11 +171,11 @@ func (s Sink) Save(slot int, objPtr interface{}) { // } // // func (x *X) StateLoad(m Source) { -// m.LoadValue(0, new(int64), func(x interface{}) { +// m.LoadValue(0, new(int64), func(x any) { // x.A = P.Foo(x.(int64)) // }) // } -func (s Sink) SaveValue(slot int, obj interface{}) { +func (s Sink) SaveValue(slot int, obj any) { s.internal.save(slot, reflect.ValueOf(obj)) } @@ -222,7 +222,7 @@ type Source struct { // Load loads the given object passed as a pointer.. // // See Sink.Save for an example. -func (s Source) Load(slot int, objPtr interface{}) { +func (s Source) Load(slot int, objPtr any) { s.internal.load(slot, reflect.ValueOf(objPtr), false, nil) } @@ -230,14 +230,14 @@ func (s Source) Load(slot int, objPtr interface{}) { // AfterLoad executions to complete prior to running this object's AfterLoad. // // See Sink.Save for an example. -func (s Source) LoadWait(slot int, objPtr interface{}) { +func (s Source) LoadWait(slot int, objPtr any) { s.internal.load(slot, reflect.ValueOf(objPtr), true, nil) } // LoadValue loads the given object value from the map. // // See Sink.SaveValue for an example. -func (s Source) LoadValue(slot int, objPtr interface{}, fn func(interface{})) { +func (s Source) LoadValue(slot int, objPtr any, fn func(any)) { o := reflect.ValueOf(objPtr) s.internal.load(slot, o, true, func() { fn(o.Elem().Interface()) }) } @@ -258,13 +258,13 @@ func (s Source) Context() context.Context { // IsZeroValue checks if the given value is the zero value. // // This function is used by the stateify tool. -func IsZeroValue(val interface{}) bool { +func IsZeroValue(val any) bool { return val == nil || reflect.ValueOf(val).Elem().IsZero() } // Failf is a wrapper around panic that should be used to generate errors that // can be caught during saving and loading. -func Failf(fmtStr string, v ...interface{}) { +func Failf(fmtStr string, v ...any) { panic(fmt.Errorf(fmtStr, v...)) } diff --git a/vendor/gvisor.dev/gvisor/pkg/state/types.go b/vendor/gvisor.dev/gvisor/pkg/state/types.go index 420675880..8df2ac64a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/state/types.go +++ b/vendor/gvisor.dev/gvisor/pkg/state/types.go @@ -180,7 +180,7 @@ func (tbd *typeDecodeDatabase) LookupType(id typeID) reflect.Type { typ, ok = primitiveTypeDatabase[name] if !ok && name == interfaceType { // Matches the built-in interface type. - var i interface{} + var i any return reflect.TypeOf(&i).Elem() } if !ok { diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/checklocks_on_unsafe.go b/vendor/gvisor.dev/gvisor/pkg/sync/checklocks_on_unsafe.go index f2bfde083..16a5d3fba 100644 --- a/vendor/gvisor.dev/gvisor/pkg/sync/checklocks_on_unsafe.go +++ b/vendor/gvisor.dev/gvisor/pkg/sync/checklocks_on_unsafe.go @@ -87,7 +87,7 @@ func noteUnlock(l unsafe.Pointer) { func dumpLocks() string { var s strings.Builder - locksHeld.Range(func(key, value interface{}) bool { + locksHeld.Range(func(key, value any) bool { goid := key.(int64) locks := value.(*gLocks) diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_ancestors_unsafe.go b/vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_ancestors_unsafe.go new file mode 100644 index 000000000..10261274e --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_ancestors_unsafe.go @@ -0,0 +1,446 @@ +package locking + +import ( + "sync/atomic" + "unsafe" + + "gvisor.dev/gvisor/pkg/gohacks" + "gvisor.dev/gvisor/pkg/sync" +) + +const ( + // ShardOrder is an optional parameter specifying the base-2 log of the + // number of shards per AtomicPtrMap. Higher values of ShardOrder reduce + // unnecessary synchronization between unrelated concurrent operations, + // improving performance for write-heavy workloads, but increase memory + // usage for small maps. + ancestorsShardOrder = 0 +) + +// Hasher is an optional type parameter. If Hasher is provided, it must define +// the Init and Hash methods. One Hasher will be shared by all AtomicPtrMaps. +type ancestorsHasher struct { + ancestorsdefaultHasher +} + +// defaultHasher is the default Hasher. This indirection exists because +// defaultHasher must exist even if a custom Hasher is provided, to prevent the +// Go compiler from complaining about defaultHasher's unused imports. +type ancestorsdefaultHasher struct { + fn func(unsafe.Pointer, uintptr) uintptr + seed uintptr +} + +// Init initializes the Hasher. +func (h *ancestorsdefaultHasher) Init() { + h.fn = sync.MapKeyHasher(map[*MutexClass]*string(nil)) + h.seed = sync.RandUintptr() +} + +// Hash returns the hash value for the given Key. +func (h *ancestorsdefaultHasher) Hash(key *MutexClass) uintptr { + return h.fn(gohacks.Noescape(unsafe.Pointer(&key)), h.seed) +} + +var ancestorshasher ancestorsHasher + +func init() { + ancestorshasher.Init() +} + +// An AtomicPtrMap maps Keys to non-nil pointers to Values. AtomicPtrMap are +// safe for concurrent use from multiple goroutines without additional +// synchronization. +// +// The zero value of AtomicPtrMap is empty (maps all Keys to nil) and ready for +// use. AtomicPtrMaps must not be copied after first use. +// +// sync.Map may be faster than AtomicPtrMap if most operations on the map are +// concurrent writes to a fixed set of keys. AtomicPtrMap is usually faster in +// other circumstances. +type ancestorsAtomicPtrMap struct { + shards [1 << ancestorsShardOrder]ancestorsapmShard +} + +func (m *ancestorsAtomicPtrMap) shard(hash uintptr) *ancestorsapmShard { + // Go defines right shifts >= width of shifted unsigned operand as 0, so + // this is correct even if ShardOrder is 0 (although nogo complains because + // nogo is dumb). + const indexLSB = unsafe.Sizeof(uintptr(0))*8 - ancestorsShardOrder + index := hash >> indexLSB + return (*ancestorsapmShard)(unsafe.Pointer(uintptr(unsafe.Pointer(&m.shards)) + (index * unsafe.Sizeof(ancestorsapmShard{})))) +} + +type ancestorsapmShard struct { + ancestorsapmShardMutationData + _ [ancestorsapmShardMutationDataPadding]byte + ancestorsapmShardLookupData + _ [ancestorsapmShardLookupDataPadding]byte +} + +type ancestorsapmShardMutationData struct { + dirtyMu sync.Mutex // serializes slot transitions out of empty + dirty uintptr // # slots with val != nil + count uintptr // # slots with val != nil and val != tombstone() + rehashMu sync.Mutex // serializes rehashing +} + +type ancestorsapmShardLookupData struct { + seq sync.SeqCount // allows atomic reads of slots+mask + slots unsafe.Pointer // [mask+1]slot or nil; protected by rehashMu/seq + mask uintptr // always (a power of 2) - 1; protected by rehashMu/seq +} + +const ( + ancestorscacheLineBytes = 64 + // Cache line padding is enabled if sharding is. + ancestorsapmEnablePadding = (ancestorsShardOrder + 63) >> 6 // 0 if ShardOrder == 0, 1 otherwise + // The -1 and +1 below are required to ensure that if unsafe.Sizeof(T) % + // cacheLineBytes == 0, then padding is 0 (rather than cacheLineBytes). + ancestorsapmShardMutationDataRequiredPadding = ancestorscacheLineBytes - (((unsafe.Sizeof(ancestorsapmShardMutationData{}) - 1) % ancestorscacheLineBytes) + 1) + ancestorsapmShardMutationDataPadding = ancestorsapmEnablePadding * ancestorsapmShardMutationDataRequiredPadding + ancestorsapmShardLookupDataRequiredPadding = ancestorscacheLineBytes - (((unsafe.Sizeof(ancestorsapmShardLookupData{}) - 1) % ancestorscacheLineBytes) + 1) + ancestorsapmShardLookupDataPadding = ancestorsapmEnablePadding * ancestorsapmShardLookupDataRequiredPadding + + // These define fractional thresholds for when apmShard.rehash() is called + // (i.e. the load factor) and when it rehases to a larger table + // respectively. They are chosen such that the rehash threshold = the + // expansion threshold + 1/2, so that when reuse of deleted slots is rare + // or non-existent, rehashing occurs after the insertion of at least 1/2 + // the table's size in new entries, which is acceptably infrequent. + ancestorsapmRehashThresholdNum = 2 + ancestorsapmRehashThresholdDen = 3 + ancestorsapmExpansionThresholdNum = 1 + ancestorsapmExpansionThresholdDen = 6 +) + +type ancestorsapmSlot struct { + // slot states are indicated by val: + // + // * Empty: val == nil; key is meaningless. May transition to full or + // evacuated with dirtyMu locked. + // + // * Full: val != nil, tombstone(), or evacuated(); key is immutable. val + // is the Value mapped to key. May transition to deleted or evacuated. + // + // * Deleted: val == tombstone(); key is still immutable. key is mapped to + // no Value. May transition to full or evacuated. + // + // * Evacuated: val == evacuated(); key is immutable. Set by rehashing on + // slots that have already been moved, requiring readers to wait for + // rehashing to complete and use the new table. Terminal state. + // + // Note that once val is non-nil, it cannot become nil again. That is, the + // transition from empty to non-empty is irreversible for a given slot; + // the only way to create more empty slots is by rehashing. + val unsafe.Pointer + key *MutexClass +} + +func ancestorsapmSlotAt(slots unsafe.Pointer, pos uintptr) *ancestorsapmSlot { + return (*ancestorsapmSlot)(unsafe.Pointer(uintptr(slots) + pos*unsafe.Sizeof(ancestorsapmSlot{}))) +} + +var ancestorstombstoneObj byte + +func ancestorstombstone() unsafe.Pointer { + return unsafe.Pointer(&ancestorstombstoneObj) +} + +var ancestorsevacuatedObj byte + +func ancestorsevacuated() unsafe.Pointer { + return unsafe.Pointer(&ancestorsevacuatedObj) +} + +// Load returns the Value stored in m for key. +func (m *ancestorsAtomicPtrMap) Load(key *MutexClass) *string { + hash := ancestorshasher.Hash(key) + shard := m.shard(hash) + +retry: + epoch := shard.seq.BeginRead() + slots := atomic.LoadPointer(&shard.slots) + mask := atomic.LoadUintptr(&shard.mask) + if !shard.seq.ReadOk(epoch) { + goto retry + } + if slots == nil { + return nil + } + + i := hash & mask + inc := uintptr(1) + for { + slot := ancestorsapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == nil { + + return nil + } + if slotVal == ancestorsevacuated() { + + goto retry + } + if slot.key == key { + if slotVal == ancestorstombstone() { + return nil + } + return (*string)(slotVal) + } + i = (i + inc) & mask + inc++ + } +} + +// Store stores the Value val for key. +func (m *ancestorsAtomicPtrMap) Store(key *MutexClass, val *string) { + m.maybeCompareAndSwap(key, false, nil, val) +} + +// Swap stores the Value val for key and returns the previously-mapped Value. +func (m *ancestorsAtomicPtrMap) Swap(key *MutexClass, val *string) *string { + return m.maybeCompareAndSwap(key, false, nil, val) +} + +// CompareAndSwap checks that the Value stored for key is oldVal; if it is, it +// stores the Value newVal for key. CompareAndSwap returns the previous Value +// stored for key, whether or not it stores newVal. +func (m *ancestorsAtomicPtrMap) CompareAndSwap(key *MutexClass, oldVal, newVal *string) *string { + return m.maybeCompareAndSwap(key, true, oldVal, newVal) +} + +func (m *ancestorsAtomicPtrMap) maybeCompareAndSwap(key *MutexClass, compare bool, typedOldVal, typedNewVal *string) *string { + hash := ancestorshasher.Hash(key) + shard := m.shard(hash) + oldVal := ancestorstombstone() + if typedOldVal != nil { + oldVal = unsafe.Pointer(typedOldVal) + } + newVal := ancestorstombstone() + if typedNewVal != nil { + newVal = unsafe.Pointer(typedNewVal) + } + +retry: + epoch := shard.seq.BeginRead() + slots := atomic.LoadPointer(&shard.slots) + mask := atomic.LoadUintptr(&shard.mask) + if !shard.seq.ReadOk(epoch) { + goto retry + } + if slots == nil { + if (compare && oldVal != ancestorstombstone()) || newVal == ancestorstombstone() { + return nil + } + + shard.rehash(nil) + goto retry + } + + i := hash & mask + inc := uintptr(1) + for { + slot := ancestorsapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == nil { + if (compare && oldVal != ancestorstombstone()) || newVal == ancestorstombstone() { + return nil + } + + shard.dirtyMu.Lock() + slotVal = atomic.LoadPointer(&slot.val) + if slotVal == nil { + + if dirty, capacity := shard.dirty+1, mask+1; dirty*ancestorsapmRehashThresholdDen >= capacity*ancestorsapmRehashThresholdNum { + shard.dirtyMu.Unlock() + shard.rehash(slots) + goto retry + } + slot.key = key + atomic.StorePointer(&slot.val, newVal) + shard.dirty++ + atomic.AddUintptr(&shard.count, 1) + shard.dirtyMu.Unlock() + return nil + } + + shard.dirtyMu.Unlock() + } + if slotVal == ancestorsevacuated() { + + goto retry + } + if slot.key == key { + + for { + if (compare && oldVal != slotVal) || newVal == slotVal { + if slotVal == ancestorstombstone() { + return nil + } + return (*string)(slotVal) + } + if atomic.CompareAndSwapPointer(&slot.val, slotVal, newVal) { + if slotVal == ancestorstombstone() { + atomic.AddUintptr(&shard.count, 1) + return nil + } + if newVal == ancestorstombstone() { + atomic.AddUintptr(&shard.count, ^uintptr(0)) + } + return (*string)(slotVal) + } + slotVal = atomic.LoadPointer(&slot.val) + if slotVal == ancestorsevacuated() { + goto retry + } + } + } + + i = (i + inc) & mask + inc++ + } +} + +// rehash is marked nosplit to avoid preemption during table copying. +// +//go:nosplit +func (shard *ancestorsapmShard) rehash(oldSlots unsafe.Pointer) { + shard.rehashMu.Lock() + defer shard.rehashMu.Unlock() + + if shard.slots != oldSlots { + + return + } + + newSize := uintptr(8) + if oldSlots != nil { + oldSize := shard.mask + 1 + newSize = oldSize + if count := atomic.LoadUintptr(&shard.count) + 1; count*ancestorsapmExpansionThresholdDen > oldSize*ancestorsapmExpansionThresholdNum { + newSize *= 2 + } + } + + newSlotsSlice := make([]ancestorsapmSlot, newSize) + newSlotsHeader := (*gohacks.SliceHeader)(unsafe.Pointer(&newSlotsSlice)) + newSlots := newSlotsHeader.Data + newMask := newSize - 1 + + shard.dirtyMu.Lock() + shard.seq.BeginWrite() + + if oldSlots != nil { + realCount := uintptr(0) + + oldMask := shard.mask + for i := uintptr(0); i <= oldMask; i++ { + oldSlot := ancestorsapmSlotAt(oldSlots, i) + val := atomic.SwapPointer(&oldSlot.val, ancestorsevacuated()) + if val == nil || val == ancestorstombstone() { + continue + } + hash := ancestorshasher.Hash(oldSlot.key) + j := hash & newMask + inc := uintptr(1) + for { + newSlot := ancestorsapmSlotAt(newSlots, j) + if newSlot.val == nil { + newSlot.val = val + newSlot.key = oldSlot.key + break + } + j = (j + inc) & newMask + inc++ + } + realCount++ + } + + shard.dirty = realCount + } + + atomic.StorePointer(&shard.slots, newSlots) + atomic.StoreUintptr(&shard.mask, newMask) + + shard.seq.EndWrite() + shard.dirtyMu.Unlock() +} + +// Range invokes f on each Key-Value pair stored in m. If any call to f returns +// false, Range stops iteration and returns. +// +// Range does not necessarily correspond to any consistent snapshot of the +// Map's contents: no Key will be visited more than once, but if the Value for +// any Key is stored or deleted concurrently, Range may reflect any mapping for +// that Key from any point during the Range call. +// +// f must not call other methods on m. +func (m *ancestorsAtomicPtrMap) Range(f func(key *MutexClass, val *string) bool) { + for si := 0; si < len(m.shards); si++ { + shard := &m.shards[si] + if !shard.doRange(f) { + return + } + } +} + +func (shard *ancestorsapmShard) doRange(f func(key *MutexClass, val *string) bool) bool { + + shard.rehashMu.Lock() + defer shard.rehashMu.Unlock() + slots := shard.slots + if slots == nil { + return true + } + mask := shard.mask + for i := uintptr(0); i <= mask; i++ { + slot := ancestorsapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == nil || slotVal == ancestorstombstone() { + continue + } + if !f(slot.key, (*string)(slotVal)) { + return false + } + } + return true +} + +// RangeRepeatable is like Range, but: +// +// - RangeRepeatable may visit the same Key multiple times in the presence of +// concurrent mutators, possibly passing different Values to f in different +// calls. +// +// - It is safe for f to call other methods on m. +func (m *ancestorsAtomicPtrMap) RangeRepeatable(f func(key *MutexClass, val *string) bool) { + for si := 0; si < len(m.shards); si++ { + shard := &m.shards[si] + + retry: + epoch := shard.seq.BeginRead() + slots := atomic.LoadPointer(&shard.slots) + mask := atomic.LoadUintptr(&shard.mask) + if !shard.seq.ReadOk(epoch) { + goto retry + } + if slots == nil { + continue + } + + for i := uintptr(0); i <= mask; i++ { + slot := ancestorsapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == ancestorsevacuated() { + goto retry + } + if slotVal == nil || slotVal == ancestorstombstone() { + continue + } + if !f(slot.key, (*string)(slotVal)) { + return + } + } + } +} diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_goroutine_unsafe.go b/vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_goroutine_unsafe.go new file mode 100644 index 000000000..f778138dc --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/sync/locking/atomicptrmap_goroutine_unsafe.go @@ -0,0 +1,446 @@ +package locking + +import ( + "sync/atomic" + "unsafe" + + "gvisor.dev/gvisor/pkg/gohacks" + "gvisor.dev/gvisor/pkg/sync" +) + +const ( + // ShardOrder is an optional parameter specifying the base-2 log of the + // number of shards per AtomicPtrMap. Higher values of ShardOrder reduce + // unnecessary synchronization between unrelated concurrent operations, + // improving performance for write-heavy workloads, but increase memory + // usage for small maps. + goroutineLocksShardOrder = 0 +) + +// Hasher is an optional type parameter. If Hasher is provided, it must define +// the Init and Hash methods. One Hasher will be shared by all AtomicPtrMaps. +type goroutineLocksHasher struct { + goroutineLocksdefaultHasher +} + +// defaultHasher is the default Hasher. This indirection exists because +// defaultHasher must exist even if a custom Hasher is provided, to prevent the +// Go compiler from complaining about defaultHasher's unused imports. +type goroutineLocksdefaultHasher struct { + fn func(unsafe.Pointer, uintptr) uintptr + seed uintptr +} + +// Init initializes the Hasher. +func (h *goroutineLocksdefaultHasher) Init() { + h.fn = sync.MapKeyHasher(map[int64]*goroutineLocks(nil)) + h.seed = sync.RandUintptr() +} + +// Hash returns the hash value for the given Key. +func (h *goroutineLocksdefaultHasher) Hash(key int64) uintptr { + return h.fn(gohacks.Noescape(unsafe.Pointer(&key)), h.seed) +} + +var goroutineLockshasher goroutineLocksHasher + +func init() { + goroutineLockshasher.Init() +} + +// An AtomicPtrMap maps Keys to non-nil pointers to Values. AtomicPtrMap are +// safe for concurrent use from multiple goroutines without additional +// synchronization. +// +// The zero value of AtomicPtrMap is empty (maps all Keys to nil) and ready for +// use. AtomicPtrMaps must not be copied after first use. +// +// sync.Map may be faster than AtomicPtrMap if most operations on the map are +// concurrent writes to a fixed set of keys. AtomicPtrMap is usually faster in +// other circumstances. +type goroutineLocksAtomicPtrMap struct { + shards [1 << goroutineLocksShardOrder]goroutineLocksapmShard +} + +func (m *goroutineLocksAtomicPtrMap) shard(hash uintptr) *goroutineLocksapmShard { + // Go defines right shifts >= width of shifted unsigned operand as 0, so + // this is correct even if ShardOrder is 0 (although nogo complains because + // nogo is dumb). + const indexLSB = unsafe.Sizeof(uintptr(0))*8 - goroutineLocksShardOrder + index := hash >> indexLSB + return (*goroutineLocksapmShard)(unsafe.Pointer(uintptr(unsafe.Pointer(&m.shards)) + (index * unsafe.Sizeof(goroutineLocksapmShard{})))) +} + +type goroutineLocksapmShard struct { + goroutineLocksapmShardMutationData + _ [goroutineLocksapmShardMutationDataPadding]byte + goroutineLocksapmShardLookupData + _ [goroutineLocksapmShardLookupDataPadding]byte +} + +type goroutineLocksapmShardMutationData struct { + dirtyMu sync.Mutex // serializes slot transitions out of empty + dirty uintptr // # slots with val != nil + count uintptr // # slots with val != nil and val != tombstone() + rehashMu sync.Mutex // serializes rehashing +} + +type goroutineLocksapmShardLookupData struct { + seq sync.SeqCount // allows atomic reads of slots+mask + slots unsafe.Pointer // [mask+1]slot or nil; protected by rehashMu/seq + mask uintptr // always (a power of 2) - 1; protected by rehashMu/seq +} + +const ( + goroutineLockscacheLineBytes = 64 + // Cache line padding is enabled if sharding is. + goroutineLocksapmEnablePadding = (goroutineLocksShardOrder + 63) >> 6 // 0 if ShardOrder == 0, 1 otherwise + // The -1 and +1 below are required to ensure that if unsafe.Sizeof(T) % + // cacheLineBytes == 0, then padding is 0 (rather than cacheLineBytes). + goroutineLocksapmShardMutationDataRequiredPadding = goroutineLockscacheLineBytes - (((unsafe.Sizeof(goroutineLocksapmShardMutationData{}) - 1) % goroutineLockscacheLineBytes) + 1) + goroutineLocksapmShardMutationDataPadding = goroutineLocksapmEnablePadding * goroutineLocksapmShardMutationDataRequiredPadding + goroutineLocksapmShardLookupDataRequiredPadding = goroutineLockscacheLineBytes - (((unsafe.Sizeof(goroutineLocksapmShardLookupData{}) - 1) % goroutineLockscacheLineBytes) + 1) + goroutineLocksapmShardLookupDataPadding = goroutineLocksapmEnablePadding * goroutineLocksapmShardLookupDataRequiredPadding + + // These define fractional thresholds for when apmShard.rehash() is called + // (i.e. the load factor) and when it rehases to a larger table + // respectively. They are chosen such that the rehash threshold = the + // expansion threshold + 1/2, so that when reuse of deleted slots is rare + // or non-existent, rehashing occurs after the insertion of at least 1/2 + // the table's size in new entries, which is acceptably infrequent. + goroutineLocksapmRehashThresholdNum = 2 + goroutineLocksapmRehashThresholdDen = 3 + goroutineLocksapmExpansionThresholdNum = 1 + goroutineLocksapmExpansionThresholdDen = 6 +) + +type goroutineLocksapmSlot struct { + // slot states are indicated by val: + // + // * Empty: val == nil; key is meaningless. May transition to full or + // evacuated with dirtyMu locked. + // + // * Full: val != nil, tombstone(), or evacuated(); key is immutable. val + // is the Value mapped to key. May transition to deleted or evacuated. + // + // * Deleted: val == tombstone(); key is still immutable. key is mapped to + // no Value. May transition to full or evacuated. + // + // * Evacuated: val == evacuated(); key is immutable. Set by rehashing on + // slots that have already been moved, requiring readers to wait for + // rehashing to complete and use the new table. Terminal state. + // + // Note that once val is non-nil, it cannot become nil again. That is, the + // transition from empty to non-empty is irreversible for a given slot; + // the only way to create more empty slots is by rehashing. + val unsafe.Pointer + key int64 +} + +func goroutineLocksapmSlotAt(slots unsafe.Pointer, pos uintptr) *goroutineLocksapmSlot { + return (*goroutineLocksapmSlot)(unsafe.Pointer(uintptr(slots) + pos*unsafe.Sizeof(goroutineLocksapmSlot{}))) +} + +var goroutineLockstombstoneObj byte + +func goroutineLockstombstone() unsafe.Pointer { + return unsafe.Pointer(&goroutineLockstombstoneObj) +} + +var goroutineLocksevacuatedObj byte + +func goroutineLocksevacuated() unsafe.Pointer { + return unsafe.Pointer(&goroutineLocksevacuatedObj) +} + +// Load returns the Value stored in m for key. +func (m *goroutineLocksAtomicPtrMap) Load(key int64) *goroutineLocks { + hash := goroutineLockshasher.Hash(key) + shard := m.shard(hash) + +retry: + epoch := shard.seq.BeginRead() + slots := atomic.LoadPointer(&shard.slots) + mask := atomic.LoadUintptr(&shard.mask) + if !shard.seq.ReadOk(epoch) { + goto retry + } + if slots == nil { + return nil + } + + i := hash & mask + inc := uintptr(1) + for { + slot := goroutineLocksapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == nil { + + return nil + } + if slotVal == goroutineLocksevacuated() { + + goto retry + } + if slot.key == key { + if slotVal == goroutineLockstombstone() { + return nil + } + return (*goroutineLocks)(slotVal) + } + i = (i + inc) & mask + inc++ + } +} + +// Store stores the Value val for key. +func (m *goroutineLocksAtomicPtrMap) Store(key int64, val *goroutineLocks) { + m.maybeCompareAndSwap(key, false, nil, val) +} + +// Swap stores the Value val for key and returns the previously-mapped Value. +func (m *goroutineLocksAtomicPtrMap) Swap(key int64, val *goroutineLocks) *goroutineLocks { + return m.maybeCompareAndSwap(key, false, nil, val) +} + +// CompareAndSwap checks that the Value stored for key is oldVal; if it is, it +// stores the Value newVal for key. CompareAndSwap returns the previous Value +// stored for key, whether or not it stores newVal. +func (m *goroutineLocksAtomicPtrMap) CompareAndSwap(key int64, oldVal, newVal *goroutineLocks) *goroutineLocks { + return m.maybeCompareAndSwap(key, true, oldVal, newVal) +} + +func (m *goroutineLocksAtomicPtrMap) maybeCompareAndSwap(key int64, compare bool, typedOldVal, typedNewVal *goroutineLocks) *goroutineLocks { + hash := goroutineLockshasher.Hash(key) + shard := m.shard(hash) + oldVal := goroutineLockstombstone() + if typedOldVal != nil { + oldVal = unsafe.Pointer(typedOldVal) + } + newVal := goroutineLockstombstone() + if typedNewVal != nil { + newVal = unsafe.Pointer(typedNewVal) + } + +retry: + epoch := shard.seq.BeginRead() + slots := atomic.LoadPointer(&shard.slots) + mask := atomic.LoadUintptr(&shard.mask) + if !shard.seq.ReadOk(epoch) { + goto retry + } + if slots == nil { + if (compare && oldVal != goroutineLockstombstone()) || newVal == goroutineLockstombstone() { + return nil + } + + shard.rehash(nil) + goto retry + } + + i := hash & mask + inc := uintptr(1) + for { + slot := goroutineLocksapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == nil { + if (compare && oldVal != goroutineLockstombstone()) || newVal == goroutineLockstombstone() { + return nil + } + + shard.dirtyMu.Lock() + slotVal = atomic.LoadPointer(&slot.val) + if slotVal == nil { + + if dirty, capacity := shard.dirty+1, mask+1; dirty*goroutineLocksapmRehashThresholdDen >= capacity*goroutineLocksapmRehashThresholdNum { + shard.dirtyMu.Unlock() + shard.rehash(slots) + goto retry + } + slot.key = key + atomic.StorePointer(&slot.val, newVal) + shard.dirty++ + atomic.AddUintptr(&shard.count, 1) + shard.dirtyMu.Unlock() + return nil + } + + shard.dirtyMu.Unlock() + } + if slotVal == goroutineLocksevacuated() { + + goto retry + } + if slot.key == key { + + for { + if (compare && oldVal != slotVal) || newVal == slotVal { + if slotVal == goroutineLockstombstone() { + return nil + } + return (*goroutineLocks)(slotVal) + } + if atomic.CompareAndSwapPointer(&slot.val, slotVal, newVal) { + if slotVal == goroutineLockstombstone() { + atomic.AddUintptr(&shard.count, 1) + return nil + } + if newVal == goroutineLockstombstone() { + atomic.AddUintptr(&shard.count, ^uintptr(0)) + } + return (*goroutineLocks)(slotVal) + } + slotVal = atomic.LoadPointer(&slot.val) + if slotVal == goroutineLocksevacuated() { + goto retry + } + } + } + + i = (i + inc) & mask + inc++ + } +} + +// rehash is marked nosplit to avoid preemption during table copying. +// +//go:nosplit +func (shard *goroutineLocksapmShard) rehash(oldSlots unsafe.Pointer) { + shard.rehashMu.Lock() + defer shard.rehashMu.Unlock() + + if shard.slots != oldSlots { + + return + } + + newSize := uintptr(8) + if oldSlots != nil { + oldSize := shard.mask + 1 + newSize = oldSize + if count := atomic.LoadUintptr(&shard.count) + 1; count*goroutineLocksapmExpansionThresholdDen > oldSize*goroutineLocksapmExpansionThresholdNum { + newSize *= 2 + } + } + + newSlotsSlice := make([]goroutineLocksapmSlot, newSize) + newSlotsHeader := (*gohacks.SliceHeader)(unsafe.Pointer(&newSlotsSlice)) + newSlots := newSlotsHeader.Data + newMask := newSize - 1 + + shard.dirtyMu.Lock() + shard.seq.BeginWrite() + + if oldSlots != nil { + realCount := uintptr(0) + + oldMask := shard.mask + for i := uintptr(0); i <= oldMask; i++ { + oldSlot := goroutineLocksapmSlotAt(oldSlots, i) + val := atomic.SwapPointer(&oldSlot.val, goroutineLocksevacuated()) + if val == nil || val == goroutineLockstombstone() { + continue + } + hash := goroutineLockshasher.Hash(oldSlot.key) + j := hash & newMask + inc := uintptr(1) + for { + newSlot := goroutineLocksapmSlotAt(newSlots, j) + if newSlot.val == nil { + newSlot.val = val + newSlot.key = oldSlot.key + break + } + j = (j + inc) & newMask + inc++ + } + realCount++ + } + + shard.dirty = realCount + } + + atomic.StorePointer(&shard.slots, newSlots) + atomic.StoreUintptr(&shard.mask, newMask) + + shard.seq.EndWrite() + shard.dirtyMu.Unlock() +} + +// Range invokes f on each Key-Value pair stored in m. If any call to f returns +// false, Range stops iteration and returns. +// +// Range does not necessarily correspond to any consistent snapshot of the +// Map's contents: no Key will be visited more than once, but if the Value for +// any Key is stored or deleted concurrently, Range may reflect any mapping for +// that Key from any point during the Range call. +// +// f must not call other methods on m. +func (m *goroutineLocksAtomicPtrMap) Range(f func(key int64, val *goroutineLocks) bool) { + for si := 0; si < len(m.shards); si++ { + shard := &m.shards[si] + if !shard.doRange(f) { + return + } + } +} + +func (shard *goroutineLocksapmShard) doRange(f func(key int64, val *goroutineLocks) bool) bool { + + shard.rehashMu.Lock() + defer shard.rehashMu.Unlock() + slots := shard.slots + if slots == nil { + return true + } + mask := shard.mask + for i := uintptr(0); i <= mask; i++ { + slot := goroutineLocksapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == nil || slotVal == goroutineLockstombstone() { + continue + } + if !f(slot.key, (*goroutineLocks)(slotVal)) { + return false + } + } + return true +} + +// RangeRepeatable is like Range, but: +// +// - RangeRepeatable may visit the same Key multiple times in the presence of +// concurrent mutators, possibly passing different Values to f in different +// calls. +// +// - It is safe for f to call other methods on m. +func (m *goroutineLocksAtomicPtrMap) RangeRepeatable(f func(key int64, val *goroutineLocks) bool) { + for si := 0; si < len(m.shards); si++ { + shard := &m.shards[si] + + retry: + epoch := shard.seq.BeginRead() + slots := atomic.LoadPointer(&shard.slots) + mask := atomic.LoadUintptr(&shard.mask) + if !shard.seq.ReadOk(epoch) { + goto retry + } + if slots == nil { + continue + } + + for i := uintptr(0); i <= mask; i++ { + slot := goroutineLocksapmSlotAt(slots, i) + slotVal := atomic.LoadPointer(&slot.val) + if slotVal == goroutineLocksevacuated() { + goto retry + } + if slotVal == nil || slotVal == goroutineLockstombstone() { + continue + } + if !f(slot.key, (*goroutineLocks)(slotVal)) { + return + } + } + } +} diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep.go b/vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep.go new file mode 100644 index 000000000..092a5765e --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep.go @@ -0,0 +1,174 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build lockdep +// +build lockdep + +package locking + +import ( + "fmt" + "reflect" + "strings" + + "gvisor.dev/gvisor/pkg/goid" + "gvisor.dev/gvisor/pkg/log" +) + +// NewMutexClass allocates a new mutex class. +func NewMutexClass(t reflect.Type, lockNames []string) *MutexClass { + c := &MutexClass{ + typ: t, + nestedLockNames: lockNames, + nestedLockClasses: make([]*MutexClass, len(lockNames)), + } + for i := range lockNames { + c.nestedLockClasses[i] = NewMutexClass(t, nil) + c.nestedLockClasses[i].lockName = lockNames[i] + } + return c +} + +// MutexClass describes dependencies of a specific class. +type MutexClass struct { + // The type of the mutex. + typ reflect.Type + + // Name of the nested lock of the above type. + lockName string + + // ancestors are locks that are locked before the current class. + ancestors ancestorsAtomicPtrMap + // nestedLockNames is a list of names for nested locks which are considered difference instances + // of the same lock class. + nestedLockNames []string + // namedLockClasses is a list of MutexClass instances of the same mutex class, but that are + // considered OK to lock simultaneously with each other, as well as with this mutex class. + // This is used for nested locking, where multiple instances of the same lock class are used + // simultaneously. + // Maps one-to-one with nestedLockNames. + nestedLockClasses []*MutexClass +} + +func (m *MutexClass) String() string { + if m.lockName == "" { + return m.typ.String() + } + return fmt.Sprintf("%s[%s]", m.typ.String(), m.lockName) +} + +type goroutineLocks map[*MutexClass]bool + +var routineLocks goroutineLocksAtomicPtrMap + +// checkLock checks that class isn't in the ancestors of prevClass. +func checkLock(class *MutexClass, prevClass *MutexClass, chain []*MutexClass) { + chain = append(chain, prevClass) + if c := prevClass.ancestors.Load(class); c != nil { + var b strings.Builder + fmt.Fprintf(&b, "WARNING: circular locking detected: %s -> %s:\n%s\n", + chain[0], class, log.LocalStack(3)) + + fmt.Fprintf(&b, "known lock chain: ") + c := class + for i := len(chain) - 1; i >= 0; i-- { + fmt.Fprintf(&b, "%s -> ", c) + c = chain[i] + } + fmt.Fprintf(&b, "%s\n", chain[0]) + c = class + for i := len(chain) - 1; i >= 0; i-- { + fmt.Fprintf(&b, "\n====== %s -> %s =====\n%s", + c, chain[i], *chain[i].ancestors.Load(c)) + c = chain[i] + } + panic(b.String()) + } + prevClass.ancestors.RangeRepeatable(func(parentClass *MutexClass, stacks *string) bool { + // The recursion is fine here. If it fails, you need to reduce + // a number of nested locks. + checkLock(class, parentClass, chain) + return true + }) +} + +// AddGLock records a lock to the current goroutine and updates dependencies. +func AddGLock(class *MutexClass, lockNameIndex int) { + gid := goid.Get() + + if lockNameIndex != -1 { + class = class.nestedLockClasses[lockNameIndex] + } + currentLocks := routineLocks.Load(gid) + if currentLocks == nil { + locks := goroutineLocks(make(map[*MutexClass]bool)) + locks[class] = true + routineLocks.Store(gid, &locks) + return + } + + // Check dependencies and add locked mutexes to the ancestors list. + for prevClass := range *currentLocks { + if prevClass == class { + panic(fmt.Sprintf("nested locking: %s:\n%s", class, log.LocalStack(2))) + } + checkLock(class, prevClass, nil) + + if c := class.ancestors.Load(prevClass); c == nil { + stacks := string(log.LocalStack(2)) + class.ancestors.Store(prevClass, &stacks) + } + } + (*currentLocks)[class] = true +} + +// DelGLock deletes a lock from the current goroutine. +func DelGLock(class *MutexClass, lockNameIndex int) { + if lockNameIndex != -1 { + class = class.nestedLockClasses[lockNameIndex] + } + gid := goid.Get() + currentLocks := routineLocks.Load(gid) + if currentLocks == nil { + panic("the current goroutine doesn't have locks") + } + if _, ok := (*currentLocks)[class]; !ok { + var b strings.Builder + fmt.Fprintf(&b, "Lock not held: %s:\n", class) + fmt.Fprintf(&b, "Current stack:\n%s\n", string(log.LocalStack(2))) + fmt.Fprintf(&b, "Current locks:\n") + for c := range *currentLocks { + heldToClass := class.ancestors.Load(c) + classToHeld := c.ancestors.Load(class) + if heldToClass == nil && classToHeld == nil { + fmt.Fprintf(&b, "\t- Holding lock: %s (no dependency to/from %s found)\n", c, class) + } else if heldToClass != nil && classToHeld != nil { + fmt.Fprintf(&b, "\t- Holding lock: %s (mutual dependency with %s found, this should never happen)\n", c, class) + } else if heldToClass != nil && classToHeld == nil { + fmt.Fprintf(&b, "\t- Holding lock: %s (dependency: %s -> %s)\n", c, c, class) + fmt.Fprintf(&b, "%s\n\n", *heldToClass) + } else if heldToClass == nil && classToHeld != nil { + fmt.Fprintf(&b, "\t- Holding lock: %s (dependency: %s -> %s)\n", c, class, c) + fmt.Fprintf(&b, "%s\n\n", *classToHeld) + } + } + fmt.Fprintf(&b, "** End of locks held **\n") + panic(b.String()) + } + + delete(*currentLocks, class) + if len(*currentLocks) == 0 { + routineLocks.Store(gid, nil) + } +} diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep_norace.go b/vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep_norace.go new file mode 100644 index 000000000..379dc9edf --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/sync/locking/lockdep_norace.go @@ -0,0 +1,42 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !lockdep +// +build !lockdep + +package locking + +import ( + "reflect" +) + +type goroutineLocks map[*MutexClass]bool + +// MutexClass is a stub class without the lockdep tag. +type MutexClass struct{} + +// NewMutexClass is no-op without the lockdep tag. +func NewMutexClass(reflect.Type, []string) *MutexClass { + return nil +} + +// AddGLock is no-op without the lockdep tag. +// +//go:inline +func AddGLock(*MutexClass, int) {} + +// DelGLock is no-op without the lockdep tag. +// +//go:inline +func DelGLock(*MutexClass, int) {} diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/locking/locking.go b/vendor/gvisor.dev/gvisor/pkg/sync/locking/locking.go new file mode 100644 index 000000000..1b99bc313 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/sync/locking/locking.go @@ -0,0 +1,28 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package locking implements lock primitives with the correctness validator. +// +// All mutexes are divided on classes and the validator check following conditions: +// - Mutexes of the same class are not taken more than once except cases when +// that is expected. +// - Mutexes are never locked in a reverse order. Lock dependencies are tracked +// on the class level. +// +// The validator is implemented in a very straightforward way. For each mutex +// class, we maintain the ancestors list of all classes that have ever been +// taken before the target one. For each goroutine, we have the list of +// currently locked mutexes. And finally, all lock methods check that +// ancestors of currently locked mutexes don't contain the target one. +package locking diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/mutex_unsafe.go b/vendor/gvisor.dev/gvisor/pkg/sync/mutex_unsafe.go index f0a471da4..9bf412700 100644 --- a/vendor/gvisor.dev/gvisor/pkg/sync/mutex_unsafe.go +++ b/vendor/gvisor.dev/gvisor/pkg/sync/mutex_unsafe.go @@ -3,62 +3,35 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.13 && !go1.21 -// +build go1.13,!go1.21 - -// When updating the build constraint (above), check that syncMutex matches the -// standard library sync.Mutex definition. - package sync import ( "sync" - "sync/atomic" "unsafe" ) // CrossGoroutineMutex is equivalent to Mutex, but it need not be unlocked by a // the same goroutine that locked the mutex. type CrossGoroutineMutex struct { - sync.Mutex -} - -type syncMutex struct { - state int32 - sema uint32 -} - -func (m *CrossGoroutineMutex) state() *int32 { - return &(*syncMutex)(unsafe.Pointer(&m.Mutex)).state + m sync.Mutex } // Lock locks the underlying Mutex. // +checklocksignore func (m *CrossGoroutineMutex) Lock() { - m.Mutex.Lock() + m.m.Lock() } // Unlock unlocks the underlying Mutex. // +checklocksignore func (m *CrossGoroutineMutex) Unlock() { - m.Mutex.Unlock() + m.m.Unlock() } -const ( - mutexUnlocked = 0 - mutexLocked = 1 -) - // TryLock tries to acquire the mutex. It returns true if it succeeds and false // otherwise. TryLock does not block. func (m *CrossGoroutineMutex) TryLock() bool { - if atomic.CompareAndSwapInt32(m.state(), mutexUnlocked, mutexLocked) { - if RaceEnabled { - RaceAcquire(unsafe.Pointer(&m.Mutex)) - } - return true - } - return false + return m.m.TryLock() } // Mutex is a mutual exclusion lock. The zero value for a Mutex is an unlocked diff --git a/vendor/gvisor.dev/gvisor/pkg/sync/runtime_unsafe.go b/vendor/gvisor.dev/gvisor/pkg/sync/runtime_unsafe.go index fc3241c5d..05239282b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/sync/runtime_unsafe.go +++ b/vendor/gvisor.dev/gvisor/pkg/sync/runtime_unsafe.go @@ -74,7 +74,7 @@ func Goready(gp uintptr, traceskip int, wakep bool) { } goready(gp, traceskip) if supportsWakeSuppression && !wakep { - preGoReadyWakeSuppression() + postGoReadyWakeSuppression() } } @@ -116,7 +116,7 @@ func RandUintptr() uintptr { // MapKeyHasher returns a hash function for pointers of m's key type. // // Preconditions: m must be a map. -func MapKeyHasher(m interface{}) func(unsafe.Pointer, uintptr) uintptr { +func MapKeyHasher(m any) func(unsafe.Pointer, uintptr) uintptr { if rtyp := reflect.TypeOf(m); rtyp.Kind() != reflect.Map { panic(fmt.Sprintf("sync.MapKeyHasher: m is %v, not map", rtyp)) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/adapters/gonet/gonet.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/adapters/gonet/gonet.go index b5426811b..6c4f3d2d0 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/adapters/gonet/gonet.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/adapters/gonet/gonet.go @@ -24,6 +24,7 @@ import ( "net" "time" + "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -453,6 +454,7 @@ func (c *TCPConn) LocalAddr() net.Addr { func (c *TCPConn) RemoteAddr() net.Addr { a, err := c.ep.GetRemoteAddress() if err != nil { + log.Warningf("ep.GetRemoteAddress() failed: %v", err) return nil } return fullToTCPAddr(a) @@ -621,6 +623,7 @@ func (c *UDPConn) newRemoteOpError(op string, remote net.Addr, err error) *net.O func (c *UDPConn) RemoteAddr() net.Addr { a, err := c.ep.GetRemoteAddress() if err != nil { + log.Warningf("ep.GetRemoteAddress() failed: %v", err) return nil } return fullToUDPAddr(a) diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum.go new file mode 100644 index 000000000..d2e019151 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum.go @@ -0,0 +1,216 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package checksum provides the implementation of the encoding and decoding of +// network protocol headers. +package checksum + +import ( + "encoding/binary" +) + +// Size is the size of a checksum. +// +// The checksum is held in a uint16 which is 2 bytes. +const Size = 2 + +// Put puts the checksum in the provided byte slice. +func Put(b []byte, xsum uint16) { + binary.BigEndian.PutUint16(b, xsum) +} + +func calculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) { + v := initial + + if odd { + v += uint32(buf[0]) + buf = buf[1:] + } + + l := len(buf) + odd = l&1 != 0 + if odd { + l-- + v += uint32(buf[l]) << 8 + } + + for i := 0; i < l; i += 2 { + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + } + + return Combine(uint16(v), uint16(v>>16)), odd +} + +func unrolledCalculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) { + v := initial + + if odd { + v += uint32(buf[0]) + buf = buf[1:] + } + + l := len(buf) + odd = l&1 != 0 + if odd { + l-- + v += uint32(buf[l]) << 8 + } + for (l - 64) >= 0 { + i := 0 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + i += 16 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + i += 16 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + i += 16 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + buf = buf[64:] + l = l - 64 + } + if (l - 32) >= 0 { + i := 0 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + i += 16 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + buf = buf[32:] + l = l - 32 + } + if (l - 16) >= 0 { + i := 0 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) + v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) + v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) + v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) + buf = buf[16:] + l = l - 16 + } + if (l - 8) >= 0 { + i := 0 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) + v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) + buf = buf[8:] + l = l - 8 + } + if (l - 4) >= 0 { + i := 0 + v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) + v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) + buf = buf[4:] + l = l - 4 + } + + // At this point since l was even before we started unrolling + // there can be only two bytes left to add. + if l != 0 { + v += (uint32(buf[0]) << 8) + uint32(buf[1]) + } + + return Combine(uint16(v), uint16(v>>16)), odd +} + +// Old calculates the checksum (as defined in RFC 1071) of the bytes in +// the given byte array. This function uses a non-optimized implementation. Its +// only retained for reference and to use as a benchmark/test. Most code should +// use the header.Checksum function. +// +// The initial checksum must have been computed on an even number of bytes. +func Old(buf []byte, initial uint16) uint16 { + s, _ := calculateChecksum(buf, false, uint32(initial)) + return s +} + +// Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the +// given byte array. This function uses an optimized unrolled version of the +// checksum algorithm. +// +// The initial checksum must have been computed on an even number of bytes. +func Checksum(buf []byte, initial uint16) uint16 { + s, _ := unrolledCalculateChecksum(buf, false, uint32(initial)) + return s +} + +// Checksumer calculates checksum defined in RFC 1071. +type Checksumer struct { + sum uint16 + odd bool +} + +// Add adds b to checksum. +func (c *Checksumer) Add(b []byte) { + if len(b) > 0 { + c.sum, c.odd = unrolledCalculateChecksum(b, c.odd, uint32(c.sum)) + } +} + +// Checksum returns the latest checksum value. +func (c *Checksumer) Checksum() uint16 { + return c.sum +} + +// Combine combines the two uint16 to form their checksum. This is done +// by adding them and the carry. +// +// Note that checksum a must have been computed on an even number of bytes. +func Combine(a, b uint16) uint16 { + v := uint32(a) + uint32(b) + return uint16(v + v>>16) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refsvfs2_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum_state_autogen.go similarity index 70% rename from vendor/gvisor.dev/gvisor/pkg/refsvfs2/refsvfs2_state_autogen.go rename to vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum_state_autogen.go index ca5fbb104..936aef749 100644 --- a/vendor/gvisor.dev/gvisor/pkg/refsvfs2/refsvfs2_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/checksum/checksum_state_autogen.go @@ -1,3 +1,3 @@ // automatically generated by stateify. -package refsvfs2 +package checksum diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/errors.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/errors.go index 2eb822822..ff0a7be4f 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/errors.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/errors.go @@ -380,19 +380,19 @@ func (*ErrNoPortAvailable) IgnoreStats() bool { } func (*ErrNoPortAvailable) String() string { return "no ports are available" } -// ErrNoRoute indicates the operation is not able to find a route to the -// destination. +// ErrHostUnreachable indicates that a destination host could not be +// reached. // // +stateify savable -type ErrNoRoute struct{} +type ErrHostUnreachable struct{} -func (*ErrNoRoute) isError() {} +func (*ErrHostUnreachable) isError() {} // IgnoreStats implements Error. -func (*ErrNoRoute) IgnoreStats() bool { +func (*ErrHostUnreachable) IgnoreStats() bool { return false } -func (*ErrNoRoute) String() string { return "no route" } +func (*ErrHostUnreachable) String() string { return "no route to host" } // ErrNoSuchFile is used to indicate that ENOENT should be returned the to // calling application. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/checksum.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/checksum.go index 419dbf217..8fc436156 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/checksum.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/checksum.go @@ -20,230 +20,23 @@ import ( "encoding/binary" "fmt" - "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) -// ChecksumSize is the size of a checksum. -// -// The checksum is held in a uint16 which is 2 bytes. -const ChecksumSize = 2 - -// PutChecksum puts the checksum in the provided byte slice. -func PutChecksum(b []byte, xsum uint16) { - binary.BigEndian.PutUint16(b, xsum) -} - -func calculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) { - v := initial - - if odd { - v += uint32(buf[0]) - buf = buf[1:] - } - - l := len(buf) - odd = l&1 != 0 - if odd { - l-- - v += uint32(buf[l]) << 8 - } - - for i := 0; i < l; i += 2 { - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - } - - return ChecksumCombine(uint16(v), uint16(v>>16)), odd -} - -func unrolledCalculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) { - v := initial - - if odd { - v += uint32(buf[0]) - buf = buf[1:] - } - - l := len(buf) - odd = l&1 != 0 - if odd { - l-- - v += uint32(buf[l]) << 8 - } - for (l - 64) >= 0 { - i := 0 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - i += 16 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - i += 16 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - i += 16 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - buf = buf[64:] - l = l - 64 - } - if (l - 32) >= 0 { - i := 0 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - i += 16 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - buf = buf[32:] - l = l - 32 - } - if (l - 16) >= 0 { - i := 0 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - v += (uint32(buf[i+8]) << 8) + uint32(buf[i+9]) - v += (uint32(buf[i+10]) << 8) + uint32(buf[i+11]) - v += (uint32(buf[i+12]) << 8) + uint32(buf[i+13]) - v += (uint32(buf[i+14]) << 8) + uint32(buf[i+15]) - buf = buf[16:] - l = l - 16 - } - if (l - 8) >= 0 { - i := 0 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - v += (uint32(buf[i+4]) << 8) + uint32(buf[i+5]) - v += (uint32(buf[i+6]) << 8) + uint32(buf[i+7]) - buf = buf[8:] - l = l - 8 - } - if (l - 4) >= 0 { - i := 0 - v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) - v += (uint32(buf[i+2]) << 8) + uint32(buf[i+3]) - buf = buf[4:] - l = l - 4 - } - - // At this point since l was even before we started unrolling - // there can be only two bytes left to add. - if l != 0 { - v += (uint32(buf[0]) << 8) + uint32(buf[1]) - } - - return ChecksumCombine(uint16(v), uint16(v>>16)), odd -} - -// ChecksumOld calculates the checksum (as defined in RFC 1071) of the bytes in -// the given byte array. This function uses a non-optimized implementation. Its -// only retained for reference and to use as a benchmark/test. Most code should -// use the header.Checksum function. -// -// The initial checksum must have been computed on an even number of bytes. -func ChecksumOld(buf []byte, initial uint16) uint16 { - s, _ := calculateChecksum(buf, false, uint32(initial)) - return s -} - -// Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the -// given byte array. This function uses an optimized unrolled version of the -// checksum algorithm. -// -// The initial checksum must have been computed on an even number of bytes. -func Checksum(buf []byte, initial uint16) uint16 { - s, _ := unrolledCalculateChecksum(buf, false, uint32(initial)) - return s -} - -// ChecksumBuffer calculates the checksum (as defined in RFC 1071) of the -// bytes in the given Buffer. -// -// The initial checksum must have been computed on an even number of bytes. -func ChecksumBuffer(buf bufferv2.Buffer, initial uint16) uint16 { - var c Checksumer - buf.Apply(func(v *bufferv2.View) { - c.Add(v.AsSlice()) - }) - return ChecksumCombine(initial, c.Checksum()) -} - -// Checksumer calculates checksum defined in RFC 1071. -type Checksumer struct { - sum uint16 - odd bool -} - -// Add adds b to checksum. -func (c *Checksumer) Add(b []byte) { - if len(b) > 0 { - c.sum, c.odd = unrolledCalculateChecksum(b, c.odd, uint32(c.sum)) - } -} - -// Checksum returns the latest checksum value. -func (c *Checksumer) Checksum() uint16 { - return c.sum -} - -// ChecksumCombine combines the two uint16 to form their checksum. This is done -// by adding them and the carry. -// -// Note that checksum a must have been computed on an even number of bytes. -func ChecksumCombine(a, b uint16) uint16 { - v := uint32(a) + uint32(b) - return uint16(v + v>>16) -} - // PseudoHeaderChecksum calculates the pseudo-header checksum for the given // destination protocol and network address. Pseudo-headers are needed by // transport layers when calculating their own checksum. func PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, srcAddr tcpip.Address, dstAddr tcpip.Address, totalLen uint16) uint16 { - xsum := Checksum([]byte(srcAddr), 0) - xsum = Checksum([]byte(dstAddr), xsum) + xsum := checksum.Checksum([]byte(srcAddr), 0) + xsum = checksum.Checksum([]byte(dstAddr), xsum) // Add the length portion of the checksum to the pseudo-checksum. tmp := make([]byte, 2) binary.BigEndian.PutUint16(tmp, totalLen) - xsum = Checksum(tmp, xsum) + xsum = checksum.Checksum(tmp, xsum) - return Checksum([]byte{0, uint8(protocol)}, xsum) + return checksum.Checksum([]byte{0, uint8(protocol)}, xsum) } // checksumUpdate2ByteAlignedUint16 updates a uint16 value in a calculated @@ -264,7 +57,7 @@ func checksumUpdate2ByteAlignedUint16(xsum, old, new uint16) uint16 { // checksum C, the new checksum C' is: // // C' = C + (-m) + m' = C + (m' - m) - return ChecksumCombine(xsum, ChecksumCombine(new, ^old)) + return checksum.Combine(xsum, checksum.Combine(new, ^old)) } // checksumUpdate2ByteAlignedAddress updates an address in a calculated diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/datagram.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/datagram.go new file mode 100644 index 000000000..7569091c5 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/datagram.go @@ -0,0 +1,18 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package header + +// DatagramMaximumSize is the maximum supported size of a single datagram. +const DatagramMaximumSize = 0xffff // 65KB. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv4.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv4.go index 85410dbd2..dd385b455 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv4.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv4.go @@ -18,6 +18,7 @@ import ( "encoding/binary" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) // ICMPv4 represents an ICMPv4 header stored in a byte array. @@ -142,8 +143,8 @@ func (b ICMPv4) Checksum() uint16 { } // SetChecksum sets the ICMP checksum field. -func (b ICMPv4) SetChecksum(checksum uint16) { - PutChecksum(b[icmpv4ChecksumOffset:], checksum) +func (b ICMPv4) SetChecksum(cs uint16) { + checksum.Put(b[icmpv4ChecksumOffset:], cs) } // SourcePort implements Transport.SourcePort. @@ -212,8 +213,8 @@ func ICMPv4Checksum(h ICMPv4, payloadCsum uint16) uint16 { xsum := payloadCsum // h[2:4] is the checksum itself, skip it to avoid checksumming the checksum. - xsum = Checksum(h[:2], xsum) - xsum = Checksum(h[4:], xsum) + xsum = checksum.Checksum(h[:2], xsum) + xsum = checksum.Checksum(h[4:], xsum) return ^xsum } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv6.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv6.go index 26b27ee07..d4b24f81b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv6.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/icmpv6.go @@ -18,6 +18,7 @@ import ( "encoding/binary" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) // ICMPv6 represents an ICMPv6 header stored in a byte array. @@ -198,8 +199,8 @@ func (b ICMPv6) Checksum() uint16 { } // SetChecksum sets the ICMP checksum field. -func (b ICMPv6) SetChecksum(checksum uint16) { - PutChecksum(b[ICMPv6ChecksumOffset:], checksum) +func (b ICMPv6) SetChecksum(cs uint16) { + checksum.Put(b[ICMPv6ChecksumOffset:], cs) } // SourcePort implements Transport.SourcePort. @@ -283,11 +284,11 @@ func ICMPv6Checksum(params ICMPv6ChecksumParams) uint16 { h := params.Header xsum := PseudoHeaderChecksum(ICMPv6ProtocolNumber, params.Src, params.Dst, uint16(len(h)+params.PayloadLen)) - xsum = ChecksumCombine(xsum, params.PayloadCsum) + xsum = checksum.Combine(xsum, params.PayloadCsum) // h[2:4] is the checksum itself, skip it to avoid checksumming the checksum. - xsum = Checksum(h[:2], xsum) - xsum = Checksum(h[4:], xsum) + xsum = checksum.Checksum(h[:2], xsum) + xsum = checksum.Checksum(h[4:], xsum) return ^xsum } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/igmp.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/igmp.go index af5b5a3d6..94c057f24 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/igmp.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/igmp.go @@ -20,6 +20,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) // IGMP represents an IGMP header stored in a byte array. @@ -169,7 +170,7 @@ func IGMPCalculateChecksum(h IGMP) uint16 { // the checksum and replace it afterwards. existingXsum := h.Checksum() h.SetChecksum(0) - xsum := ^Checksum(h, 0) + xsum := ^checksum.Checksum(h, 0) h.SetChecksum(existingXsum) return xsum } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/ipv4.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/ipv4.go index 6c6ecd1ff..16a63a46d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/ipv4.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/ipv4.go @@ -20,6 +20,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) // RFC 971 defines the fields of the IPv4 header on page 11 using the following @@ -50,7 +51,7 @@ const ( flagsFO = 6 ttl = 8 protocol = 9 - checksum = 10 + xsum = 10 srcAddr = 12 dstAddr = 16 options = 20 @@ -301,7 +302,7 @@ func (b IPv4) TotalLength() uint16 { // Checksum returns the checksum field of the IPv4 header. func (b IPv4) Checksum() uint16 { - return binary.BigEndian.Uint16(b[checksum:]) + return binary.BigEndian.Uint16(b[xsum:]) } // SourceAddress returns the "source address" field of the IPv4 header. @@ -382,7 +383,7 @@ func (b IPv4) SetTotalLength(totalLength uint16) { // SetChecksum sets the checksum field of the IPv4 header. func (b IPv4) SetChecksum(v uint16) { - PutChecksum(b[checksum:], v) + checksum.Put(b[xsum:], v) } // SetFlagsFragmentOffset sets the "flags" and "fragment offset" fields of the @@ -410,7 +411,7 @@ func (b IPv4) SetDestinationAddress(addr tcpip.Address) { // CalculateChecksum calculates the checksum of the IPv4 header. func (b IPv4) CalculateChecksum() uint16 { - return Checksum(b[:b.HeaderLength()], 0) + return checksum.Checksum(b[:b.HeaderLength()], 0) } // Encode encodes all the fields of the IPv4 header. @@ -444,8 +445,8 @@ func (b IPv4) Encode(i *IPv4Fields) { // packets are produced. func (b IPv4) EncodePartial(partialChecksum, totalLength uint16) { b.SetTotalLength(totalLength) - checksum := Checksum(b[IPv4TotalLenOffset:IPv4TotalLenOffset+2], partialChecksum) - b.SetChecksum(^checksum) + xsum := checksum.Checksum(b[IPv4TotalLenOffset:IPv4TotalLenOffset+2], partialChecksum) + b.SetChecksum(^xsum) } // IsValid performs basic validation on the packet. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/parse/parse.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/parse/parse.go index dc1300528..0e29377cc 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/parse/parse.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/parse/parse.go @@ -27,7 +27,7 @@ import ( // pkt.Data. // // Returns true if the header was successfully parsed. -func ARP(pkt *stack.PacketBuffer) bool { +func ARP(pkt stack.PacketBufferPtr) bool { _, ok := pkt.NetworkHeader().Consume(header.ARPSize) if ok { pkt.NetworkProtocolNumber = header.ARPProtocolNumber @@ -39,7 +39,7 @@ func ARP(pkt *stack.PacketBuffer) bool { // header with the IPv4 header. // // Returns true if the header was successfully parsed. -func IPv4(pkt *stack.PacketBuffer) bool { +func IPv4(pkt stack.PacketBufferPtr) bool { hdr, ok := pkt.Data().PullUp(header.IPv4MinimumSize) if !ok { return false @@ -71,7 +71,7 @@ func IPv4(pkt *stack.PacketBuffer) bool { // IPv6 parses an IPv6 packet found in pkt.Data and populates pkt's network // header with the IPv6 header. -func IPv6(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, fragID uint32, fragOffset uint16, fragMore bool, ok bool) { +func IPv6(pkt stack.PacketBufferPtr) (proto tcpip.TransportProtocolNumber, fragID uint32, fragOffset uint16, fragMore bool, ok bool) { hdr, ok := pkt.Data().PullUp(header.IPv6MinimumSize) if !ok { return 0, 0, 0, false, false @@ -157,7 +157,7 @@ traverseExtensions: // header with the UDP header. // // Returns true if the header was successfully parsed. -func UDP(pkt *stack.PacketBuffer) bool { +func UDP(pkt stack.PacketBufferPtr) bool { _, ok := pkt.TransportHeader().Consume(header.UDPMinimumSize) pkt.TransportProtocolNumber = header.UDPProtocolNumber return ok @@ -167,7 +167,7 @@ func UDP(pkt *stack.PacketBuffer) bool { // header with the TCP header. // // Returns true if the header was successfully parsed. -func TCP(pkt *stack.PacketBuffer) bool { +func TCP(pkt stack.PacketBufferPtr) bool { // TCP header is variable length, peek at it first. hdrLen := header.TCPMinimumSize hdr, ok := pkt.Data().PullUp(hdrLen) @@ -191,7 +191,7 @@ func TCP(pkt *stack.PacketBuffer) bool { // if present. // // Returns true if an ICMPv4 header was successfully parsed. -func ICMPv4(pkt *stack.PacketBuffer) bool { +func ICMPv4(pkt stack.PacketBufferPtr) bool { if _, ok := pkt.TransportHeader().Consume(header.ICMPv4MinimumSize); ok { pkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber return true @@ -203,7 +203,7 @@ func ICMPv4(pkt *stack.PacketBuffer) bool { // if present. // // Returns true if an ICMPv6 header was successfully parsed. -func ICMPv6(pkt *stack.PacketBuffer) bool { +func ICMPv6(pkt stack.PacketBufferPtr) bool { hdr, ok := pkt.Data().PullUp(header.ICMPv6MinimumSize) if !ok { return false diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/tcp.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/tcp.go index ed4952319..2d38928ce 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/tcp.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/tcp.go @@ -19,6 +19,7 @@ import ( "github.com/google/btree" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/seqnum" ) @@ -300,8 +301,8 @@ func (b TCP) SetDestinationPort(port uint16) { } // SetChecksum sets the checksum field of the TCP header. -func (b TCP) SetChecksum(checksum uint16) { - PutChecksum(b[TCPChecksumOffset:], checksum) +func (b TCP) SetChecksum(xsum uint16) { + checksum.Put(b[TCPChecksumOffset:], xsum) } // SetDataOffset sets the data offset field of the TCP header. headerLen should @@ -340,13 +341,13 @@ func (b TCP) SetUrgentPointer(urgentPointer uint16) { // and the checksum of the segment data. func (b TCP) CalculateChecksum(partialChecksum uint16) uint16 { // Calculate the rest of the checksum. - return Checksum(b[:b.DataOffset()], partialChecksum) + return checksum.Checksum(b[:b.DataOffset()], partialChecksum) } // IsChecksumValid returns true iff the TCP header's checksum is valid. func (b TCP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum, payloadLength uint16) bool { xsum := PseudoHeaderChecksum(TCPProtocolNumber, src, dst, uint16(b.DataOffset())+payloadLength) - xsum = ChecksumCombine(xsum, payloadChecksum) + xsum = checksum.Combine(xsum, payloadChecksum) return b.CalculateChecksum(xsum) == 0xffff } @@ -389,17 +390,17 @@ func (b TCP) EncodePartial(partialChecksum, length uint16, seqnum, acknum uint32 tmp := make([]byte, 4) binary.BigEndian.PutUint16(tmp, length) binary.BigEndian.PutUint16(tmp[2:], uint16(flags)) - checksum := Checksum(tmp, partialChecksum) + xsum := checksum.Checksum(tmp, partialChecksum) // Encode the passed-in fields. b.encodeSubset(seqnum, acknum, flags, rcvwnd) // Add the contributions of the passed-in fields to the checksum. - checksum = Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], checksum) - checksum = Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], checksum) + xsum = checksum.Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], xsum) + xsum = checksum.Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], xsum) // Encode the checksum. - b.SetChecksum(^checksum) + b.SetChecksum(^xsum) } // SetSourcePortWithChecksumUpdate implements ChecksummableTransport. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/udp.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/udp.go index cdd76acdb..036838dbb 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/header/udp.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/header/udp.go @@ -19,6 +19,7 @@ import ( "math" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" ) const ( @@ -100,8 +101,8 @@ func (b UDP) SetDestinationPort(port uint16) { } // SetChecksum sets the "checksum" field of the UDP header. -func (b UDP) SetChecksum(checksum uint16) { - PutChecksum(b[udpChecksum:], checksum) +func (b UDP) SetChecksum(xsum uint16) { + checksum.Put(b[udpChecksum:], xsum) } // SetLength sets the "length" field of the UDP header. @@ -113,13 +114,13 @@ func (b UDP) SetLength(length uint16) { // checksum of the network-layer pseudo-header and the checksum of the payload. func (b UDP) CalculateChecksum(partialChecksum uint16) uint16 { // Calculate the rest of the checksum. - return Checksum(b[:UDPMinimumSize], partialChecksum) + return checksum.Checksum(b[:UDPMinimumSize], partialChecksum) } // IsChecksumValid returns true iff the UDP header's checksum is valid. func (b UDP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum uint16) bool { xsum := PseudoHeaderChecksum(UDPProtocolNumber, dst, src, b.Length()) - xsum = ChecksumCombine(xsum, payloadChecksum) + xsum = checksum.Combine(xsum, payloadChecksum) return b.CalculateChecksum(xsum) == 0xffff } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/link/nested/nested.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/link/nested/nested.go index 79b407d8a..cbf1ffc53 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/link/nested/nested.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/link/nested/nested.go @@ -51,7 +51,7 @@ func (e *Endpoint) Init(child stack.LinkEndpoint, embedder stack.NetworkDispatch } // DeliverNetworkPacket implements stack.NetworkDispatcher. -func (e *Endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func (e *Endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { e.mu.RLock() d := e.dispatcher e.mu.RUnlock() @@ -61,7 +61,7 @@ func (e *Endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pk } // DeliverLinkPacket implements stack.NetworkDispatcher. -func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer, incoming bool) { +func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr, incoming bool) { e.mu.RLock() d := e.dispatcher e.mu.RUnlock() @@ -144,6 +144,6 @@ func (e *Endpoint) ARPHardwareType() header.ARPHardwareType { } // AddHeader implements stack.LinkEndpoint.AddHeader. -func (e *Endpoint) AddHeader(pkt *stack.PacketBuffer) { +func (e *Endpoint) AddHeader(pkt stack.PacketBufferPtr) { e.child.AddHeader(pkt) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/pcap.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/pcap.go index 491957ac8..648852b24 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/pcap.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/pcap.go @@ -50,7 +50,7 @@ var _ encoding.BinaryMarshaler = (*pcapPacket)(nil) type pcapPacket struct { timestamp time.Time - packet *stack.PacketBuffer + packet stack.PacketBufferPtr maxCaptureLen int } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go index 566ef5032..470a57bc2 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go @@ -133,12 +133,12 @@ func NewWithWriter(lower stack.LinkEndpoint, writer io.Writer, snapLen uint32) ( // DeliverNetworkPacket implements the stack.NetworkDispatcher interface. It is // called by the link-layer endpoint being wrapped when a packet arrives, and // logs the packet before forwarding to the actual dispatcher. -func (e *endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func (e *endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { e.dumpPacket(DirectionRecv, protocol, pkt) e.Endpoint.DeliverNetworkPacket(protocol, pkt) } -func (e *endpoint) dumpPacket(dir Direction, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func (e *endpoint) dumpPacket(dir Direction, protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { writer := e.writer if writer == nil && LogPackets.Load() == 1 { LogPacket(e.logPrefix, dir, protocol, pkt) @@ -170,7 +170,7 @@ func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) } // LogPacket logs a packet to stdout. -func LogPacket(prefix string, dir Direction, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func LogPacket(prefix string, dir Direction, protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { // Figure out the network layer info. var transProto uint8 src := tcpip.Address("unknown") @@ -380,7 +380,7 @@ func LogPacket(prefix string, dir Direction, protocol tcpip.NetworkProtocolNumbe // trimmedClone clones the packet buffer to not modify the original. It trims // anything before the network header. -func trimmedClone(pkt *stack.PacketBuffer) *stack.PacketBuffer { +func trimmedClone(pkt stack.PacketBufferPtr) stack.PacketBufferPtr { // We don't clone the original packet buffer so that the new packet buffer // does not have any of its headers set. // diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/arp/arp.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/arp/arp.go index 674ef5184..1f1489993 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/arp/arp.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/arp/arp.go @@ -133,7 +133,7 @@ func (e *endpoint) MaxHeaderLength() uint16 { func (*endpoint) Close() {} -func (*endpoint) WritePacket(*stack.Route, stack.NetworkHeaderParams, *stack.PacketBuffer) tcpip.Error { +func (*endpoint) WritePacket(*stack.Route, stack.NetworkHeaderParams, stack.PacketBufferPtr) tcpip.Error { return &tcpip.ErrNotSupported{} } @@ -142,11 +142,11 @@ func (*endpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNumber { return ProtocolNumber } -func (*endpoint) WriteHeaderIncludedPacket(*stack.Route, *stack.PacketBuffer) tcpip.Error { +func (*endpoint) WriteHeaderIncludedPacket(*stack.Route, stack.PacketBufferPtr) tcpip.Error { return &tcpip.ErrNotSupported{} } -func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { +func (e *endpoint) HandlePacket(pkt stack.PacketBufferPtr) { stats := e.stats.arp stats.packetsReceived.Increment() @@ -384,7 +384,7 @@ func (*protocol) Close() {} func (*protocol) Wait() {} // Parse implements stack.NetworkProtocol.Parse. -func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) { +func (*protocol) Parse(pkt stack.PacketBufferPtr) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) { return 0, false, parse.ARP(pkt) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/fragmentation.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/fragmentation.go index fecda178b..86695d73b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/fragmentation.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/fragmentation.go @@ -97,7 +97,7 @@ type TimeoutHandler interface { // OnReassemblyTimeout will be called with the first fragment (or nil, if the // first fragment has not been received) of a packet whose reassembly has // timed out. - OnReassemblyTimeout(pkt *stack.PacketBuffer) + OnReassemblyTimeout(pkt stack.PacketBufferPtr) } // NewFragmentation creates a new Fragmentation. @@ -155,28 +155,28 @@ func NewFragmentation(blockSize uint16, highMemoryLimit, lowMemoryLimit int, rea // to be given here outside of the FragmentID struct because IPv6 should not use // the protocol to identify a fragment. func (f *Fragmentation) Process( - id FragmentID, first, last uint16, more bool, proto uint8, pkt *stack.PacketBuffer) ( - *stack.PacketBuffer, uint8, bool, error) { + id FragmentID, first, last uint16, more bool, proto uint8, pkt stack.PacketBufferPtr) ( + stack.PacketBufferPtr, uint8, bool, error) { if first > last { - return nil, 0, false, fmt.Errorf("first=%d is greater than last=%d: %w", first, last, ErrInvalidArgs) + return stack.PacketBufferPtr{}, 0, false, fmt.Errorf("first=%d is greater than last=%d: %w", first, last, ErrInvalidArgs) } if first%f.blockSize != 0 { - return nil, 0, false, fmt.Errorf("first=%d is not a multiple of block size=%d: %w", first, f.blockSize, ErrInvalidArgs) + return stack.PacketBufferPtr{}, 0, false, fmt.Errorf("first=%d is not a multiple of block size=%d: %w", first, f.blockSize, ErrInvalidArgs) } fragmentSize := last - first + 1 if more && fragmentSize%f.blockSize != 0 { - return nil, 0, false, fmt.Errorf("fragment size=%d bytes is not a multiple of block size=%d on non-final fragment: %w", fragmentSize, f.blockSize, ErrInvalidArgs) + return stack.PacketBufferPtr{}, 0, false, fmt.Errorf("fragment size=%d bytes is not a multiple of block size=%d on non-final fragment: %w", fragmentSize, f.blockSize, ErrInvalidArgs) } if l := pkt.Data().Size(); l != int(fragmentSize) { - return nil, 0, false, fmt.Errorf("got fragment size=%d bytes not equal to the expected fragment size=%d bytes (first=%d last=%d): %w", l, fragmentSize, first, last, ErrInvalidArgs) + return stack.PacketBufferPtr{}, 0, false, fmt.Errorf("got fragment size=%d bytes not equal to the expected fragment size=%d bytes (first=%d last=%d): %w", l, fragmentSize, first, last, ErrInvalidArgs) } f.mu.Lock() if f.reassemblers == nil { - return nil, 0, false, fmt.Errorf("Release() called before fragmentation processing could finish") + return stack.PacketBufferPtr{}, 0, false, fmt.Errorf("Release() called before fragmentation processing could finish") } r, ok := f.reassemblers[id] @@ -201,7 +201,7 @@ func (f *Fragmentation) Process( f.mu.Lock() f.release(r, false /* timedOut */) f.mu.Unlock() - return nil, 0, false, fmt.Errorf("fragmentation processing error: %w", err) + return stack.PacketBufferPtr{}, 0, false, fmt.Errorf("fragmentation processing error: %w", err) } f.mu.Lock() f.memSize += memConsumed @@ -251,14 +251,14 @@ func (f *Fragmentation) release(r *reassembler, timedOut bool) { if h := f.timeoutHandler; timedOut && h != nil { h.OnReassemblyTimeout(r.pkt) } - if r.pkt != nil { + if !r.pkt.IsNil() { r.pkt.DecRef() - r.pkt = nil + r.pkt = stack.PacketBufferPtr{} } for _, h := range r.holes { - if h.pkt != nil { + if !h.pkt.IsNil() { h.pkt.DecRef() - h.pkt = nil + h.pkt = stack.PacketBufferPtr{} } } r.holes = nil @@ -308,7 +308,7 @@ type PacketFragmenter struct { // // reserve is the number of bytes that should be reserved for the headers in // each generated fragment. -func MakePacketFragmenter(pkt *stack.PacketBuffer, fragmentPayloadLen uint32, reserve int) PacketFragmenter { +func MakePacketFragmenter(pkt stack.PacketBufferPtr, fragmentPayloadLen uint32, reserve int) PacketFragmenter { // As per RFC 8200 Section 4.5, some IPv6 extension headers should not be // repeated in each fragment. However we do not currently support any header // of that kind yet, so the following computation is valid for both IPv4 and @@ -339,7 +339,7 @@ func MakePacketFragmenter(pkt *stack.PacketBuffer, fragmentPayloadLen uint32, re // Note that the returned packet will not have its network and link headers // populated, but space for them will be reserved. The transport header will be // stored in the packet's data. -func (pf *PacketFragmenter) BuildNextFragment() (*stack.PacketBuffer, int, int, bool) { +func (pf *PacketFragmenter) BuildNextFragment() (stack.PacketBufferPtr, int, int, bool) { if pf.currentFragment >= pf.fragmentCount { panic("BuildNextFragment should not be called again after the last fragment was returned") } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/reassembler.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/reassembler.go index b7dace247..a9ba0587b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/reassembler.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/fragmentation/reassembler.go @@ -30,7 +30,7 @@ type hole struct { final bool // pkt is the fragment packet if hole is filled. We keep the whole pkt rather // than the fragmented payload to prevent binding to specific buffer types. - pkt *stack.PacketBuffer + pkt stack.PacketBufferPtr } type reassembler struct { @@ -43,7 +43,7 @@ type reassembler struct { filled int done bool createdAt tcpip.MonotonicTime - pkt *stack.PacketBuffer + pkt stack.PacketBufferPtr } func newReassembler(id FragmentID, clock tcpip.Clock) *reassembler { @@ -60,14 +60,14 @@ func newReassembler(id FragmentID, clock tcpip.Clock) *reassembler { return r } -func (r *reassembler) process(first, last uint16, more bool, proto uint8, pkt *stack.PacketBuffer) (*stack.PacketBuffer, uint8, bool, int, error) { +func (r *reassembler) process(first, last uint16, more bool, proto uint8, pkt stack.PacketBufferPtr) (stack.PacketBufferPtr, uint8, bool, int, error) { r.mu.Lock() defer r.mu.Unlock() if r.done { // A concurrent goroutine might have already reassembled // the packet and emptied the heap while this goroutine // was waiting on the mutex. We don't have to do anything in this case. - return nil, 0, false, 0, nil + return stack.PacketBufferPtr{}, 0, false, 0, nil } var holeFound bool @@ -91,12 +91,12 @@ func (r *reassembler) process(first, last uint16, more bool, proto uint8, pkt *s // https://github.com/torvalds/linux/blob/38525c6/net/ipv4/inet_fragment.c#L349 if first < currentHole.first || currentHole.last < last { // Incoming fragment only partially fits in the free hole. - return nil, 0, false, 0, ErrFragmentOverlap + return stack.PacketBufferPtr{}, 0, false, 0, ErrFragmentOverlap } if !more { if !currentHole.final || currentHole.filled && currentHole.last != last { // We have another final fragment, which does not perfectly overlap. - return nil, 0, false, 0, ErrFragmentConflict + return stack.PacketBufferPtr{}, 0, false, 0, ErrFragmentConflict } } @@ -145,7 +145,7 @@ func (r *reassembler) process(first, last uint16, more bool, proto uint8, pkt *s // options received in the first fragment should be used - and they should // override options from following fragments. if first == 0 { - if r.pkt != nil { + if !r.pkt.IsNil() { r.pkt.DecRef() } r.pkt = pkt.IncRef() @@ -155,19 +155,19 @@ func (r *reassembler) process(first, last uint16, more bool, proto uint8, pkt *s } if !holeFound { // Incoming fragment is beyond end. - return nil, 0, false, 0, ErrFragmentConflict + return stack.PacketBufferPtr{}, 0, false, 0, ErrFragmentConflict } // Check if all the holes have been filled and we are ready to reassemble. if r.filled < len(r.holes) { - return nil, 0, false, memConsumed, nil + return stack.PacketBufferPtr{}, 0, false, memConsumed, nil } sort.Slice(r.holes, func(i, j int) bool { return r.holes[i].first < r.holes[j].first }) - resPkt := r.holes[0].pkt.IncRef() + resPkt := r.holes[0].pkt.Clone() for i := 1; i < len(r.holes); i++ { stack.MergeFragment(resPkt, r.holes[i].pkt) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/errors.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/errors.go index 62f111750..5ff59fd59 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/errors.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/errors.go @@ -58,12 +58,12 @@ func (*ErrLinkLocalDestinationAddress) isForwardingError() {} func (*ErrLinkLocalDestinationAddress) String() string { return "link local destination address" } -// ErrNoRoute indicates that a route for the received packet couldn't be found. -type ErrNoRoute struct{} +// ErrHostUnreachable indicates that the destinatino host could not be reached. +type ErrHostUnreachable struct{} -func (*ErrNoRoute) isForwardingError() {} +func (*ErrHostUnreachable) isForwardingError() {} -func (*ErrNoRoute) String() string { return "no route" } +func (*ErrHostUnreachable) String() string { return "no route to host" } // ErrMessageTooLong indicates the packet was too big for the outgoing MTU. // diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go index 3d196e85a..428907e94 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go @@ -23,93 +23,61 @@ import ( "gvisor.dev/gvisor/pkg/tcpip" ) -// hostState is the state a host may be in for a multicast group. -type hostState int - -// The states below are generic across IGMPv2 (RFC 2236 section 6) and MLDv1 -// (RFC 2710 section 5). Even though the states are generic across both IGMPv2 -// and MLDv1, IGMPv2 terminology will be used. -// -// ______________receive query______________ -// | | -// | _____send or receive report_____ | -// | | | | -// V | V | -// +-------+ +-----------+ +------------+ +-------------------+ +--------+ | -// | Non-M | | Pending-M | | Delaying-M | | Queued Delaying-M | | Idle-M | - -// +-------+ +-----------+ +------------+ +-------------------+ +--------+ -// | ^ | ^ | ^ | ^ -// | | | | | | | | -// ---------- ------- ---------- ------------- -// initialize new send inital fail to send send or receive -// group membership report delayed report report -// -// Not shown in the diagram above, but any state may transition into the non -// member state when a group is left. const ( - // nonMember is the "'Non-Member' state, when the host does not belong to the - // group on the interface. This is the initial state for all memberships on - // all network interfaces; it requires no storage in the host." - // - // 'Non-Listener' is the MLDv1 term used to describe this state. - // - // This state is used to keep track of groups that have been joined locally, - // but without advertising the membership to the network. - nonMember hostState = iota - - // pendingMember is a newly joined member that is waiting to successfully send - // the initial set of reports. - // - // This is not an RFC defined state; it is an implementation specific state to - // track that the initial report needs to be sent. + // As per RFC 2236 section 3, // - // MAY NOT transition to the idle member state from this state. - pendingMember - - // delayingMember is the "'Delaying Member' state, when the host belongs to - // the group on the interface and has a report delay timer running for that - // membership." - // - // 'Delaying Listener' is the MLDv1 term used to describe this state. - delayingMember - - // queuedDelayingMember is a delayingMember that failed to send a report after - // its delayed report timer fired. Hosts in this state are waiting to attempt - // retransmission of the delayed report. + // When a host joins a multicast group, it should immediately transmit + // an unsolicited Version 2 Membership Report for that group, in case it + // is the first member of that group on the network. To cover the + // possibility of the initial Membership Report being lost or damaged, + // it is recommended that it be repeated once or twice after short + // delays [Unsolicited Report Interval]. (A simple way to accomplish + // this is to send the initial Version 2 Membership Report and then act + // as if a Group-Specific Query was received for that group, and set a + // timer appropriately). // - // This is not an RFC defined state; it is an implementation specific state to - // track that the delayed report needs to be sent. + // As per RFC 2710 section 4, // - // May transition to idle member if a report is received for a group. - queuedDelayingMember - - // idleMember is the "Idle Member" state, when the host belongs to the group - // on the interface and does not have a report delay timer running for that - // membership. - // - // 'Idle Listener' is the MLDv1 term used to describe this state. - idleMember + // When a node starts listening to a multicast address on an interface, + // it should immediately transmit an unsolicited Report for that address + // on that interface, in case it is the first listener on the link. To + // cover the possibility of the initial Report being lost or damaged, it + // is recommended that it be repeated once or twice after short delays + // [Unsolicited Report Interval]. (A simple way to accomplish this is + // to send the initial Report and then act as if a Multicast-Address- + // Specific Query was received for that address, and set a timer + // appropriately). + unsolicitedTransmissionCount = 2 + + // Responses to queries may be delayed, but we only send a response to a + // query once. A response to a query can be handled by any pending + // unsolicited transmission count, but we should send at least one report + // after sending a query. + // + // As per RFC 2236 section 3, + // + // When a host receives a General Query, it sets delay timers for each + // group (excluding the all-systems group) of which it is a member on + // the interface from which it received the query. + // + // As per RFC 2710 section 4, + // + // When a node receives a General Query, it sets a delay timer for each + // multicast address to which it is listening on the interface from + // which it received the Query, EXCLUDING the link-scope all-nodes + // address and any multicast addresses of scope 0 (reserved) or 1 + // (node-local). + minQueryResponseTransmissionCount = 1 ) -func (s hostState) isDelayingMember() bool { - switch s { - case nonMember, pendingMember, idleMember: - return false - case delayingMember, queuedDelayingMember: - return true - default: - panic(fmt.Sprintf("unrecognized host state = %d", s)) - } -} - // multicastGroupState holds the Generic Multicast Protocol state for a // multicast group. type multicastGroupState struct { // joins is the number of times the group has been joined. joins uint64 - // state holds the host's state for the group. - state hostState + // transmissionLeft is the number of transmissions left to send. + transmissionLeft uint // lastToSendReport is true if we sent the last report for the group. It is // used to track whether there are other hosts on the subnet that are also @@ -135,6 +103,7 @@ type multicastGroupState struct { func (m *multicastGroupState) cancelDelayedReportJob() { m.delayedReportJob.Cancel() m.delayedReportJobFiresAt = time.Time{} + m.transmissionLeft = 0 } // GenericMulticastProtocolOptions holds options for the generic multicast @@ -281,20 +250,10 @@ func (g *GenericMulticastProtocolState) InitializeGroupsLocked() { // Precondition: g.protocolMU must be locked. func (g *GenericMulticastProtocolState) SendQueuedReportsLocked() { for groupAddress, info := range g.memberships { - switch info.state { - case nonMember, delayingMember, idleMember: - case pendingMember: - // pendingMembers failed to send their initial unsolicited report so try - // to send the report and queue the extra unsolicited reports. - g.maybeSendInitialReportLocked(groupAddress, &info) - case queuedDelayingMember: - // queuedDelayingMembers failed to send their delayed reports so try to - // send the report and transition them to the idle state. - g.maybeSendDelayedReportLocked(groupAddress, &info) - default: - panic(fmt.Sprintf("unrecognized host state = %d", info.state)) + if info.delayedReportJobFiresAt.IsZero() { + g.maybeSendReportLocked(groupAddress, &info) + g.memberships[groupAddress] = info } - g.memberships[groupAddress] = info } } @@ -311,9 +270,7 @@ func (g *GenericMulticastProtocolState) JoinGroupLocked(groupAddress tcpip.Addre info := multicastGroupState{ // Since we just joined the group, its count is 1. - joins: 1, - // The state will be updated below, if required. - state: nonMember, + joins: 1, lastToSendReport: false, delayedReportJob: tcpip.NewJob(g.opts.Clock, g.protocolMU, func() { if !g.opts.Protocol.Enabled() { @@ -325,7 +282,8 @@ func (g *GenericMulticastProtocolState) JoinGroupLocked(groupAddress tcpip.Addre panic(fmt.Sprintf("expected to find group state for group = %s", groupAddress)) } - g.maybeSendDelayedReportLocked(groupAddress, &info) + info.delayedReportJobFiresAt = time.Time{} + g.maybeSendReportLocked(groupAddress, &info) g.memberships[groupAddress] = info }), } @@ -400,11 +358,11 @@ func (g *GenericMulticastProtocolState) HandleQueryLocked(groupAddress tcpip.Add if groupAddress.Unspecified() { // This is a general query as the group address is unspecified. for groupAddress, info := range g.memberships { - g.setDelayTimerForAddressRLocked(groupAddress, &info, maxResponseTime) + g.setDelayTimerForAddressLocked(groupAddress, &info, maxResponseTime) g.memberships[groupAddress] = info } } else if info, ok := g.memberships[groupAddress]; ok { - g.setDelayTimerForAddressRLocked(groupAddress, &info, maxResponseTime) + g.setDelayTimerForAddressLocked(groupAddress, &info, maxResponseTime) g.memberships[groupAddress] = info } } @@ -432,10 +390,9 @@ func (g *GenericMulticastProtocolState) HandleReportLocked(groupAddress tcpip.Ad // multicast address while it has a timer running for that same address // on that interface, it stops its timer and does not send a Report for // that address, thus suppressing duplicate reports on the link. - if info, ok := g.memberships[groupAddress]; ok && info.state.isDelayingMember() { + if info, ok := g.memberships[groupAddress]; ok { info.cancelDelayedReportJob() info.lastToSendReport = false - info.state = idleMember g.memberships[groupAddress] = info } } @@ -444,30 +401,23 @@ func (g *GenericMulticastProtocolState) HandleReportLocked(groupAddress tcpip.Ad // // Precondition: g.protocolMU must be locked. func (g *GenericMulticastProtocolState) initializeNewMemberLocked(groupAddress tcpip.Address, info *multicastGroupState) { - if info.state != nonMember { - panic(fmt.Sprintf("host must be in non-member state to be initialized; group = %s, state = %d", groupAddress, info.state)) - } - info.lastToSendReport = false - - if !g.opts.Protocol.ShouldPerformProtocol(groupAddress) { - info.state = idleMember - return + if g.shouldPerformForGroup(groupAddress) { + info.transmissionLeft = unsolicitedTransmissionCount + g.maybeSendReportLocked(groupAddress, info) } +} - info.state = pendingMember - g.maybeSendInitialReportLocked(groupAddress, info) +func (g *GenericMulticastProtocolState) shouldPerformForGroup(groupAddress tcpip.Address) bool { + return g.opts.Protocol.ShouldPerformProtocol(groupAddress) && g.opts.Protocol.Enabled() } -// maybeSendInitialReportLocked attempts to start transmission of the initial -// set of reports after newly joining a group. -// -// Host must be in pending member state. +// maybeSendReportLocked attempts to send a report for a group. // // Precondition: g.protocolMU must be locked. -func (g *GenericMulticastProtocolState) maybeSendInitialReportLocked(groupAddress tcpip.Address, info *multicastGroupState) { - if info.state != pendingMember { - panic(fmt.Sprintf("host must be in pending member state to send initial reports; group = %s, state = %d", groupAddress, info.state)) +func (g *GenericMulticastProtocolState) maybeSendReportLocked(groupAddress tcpip.Address, info *multicastGroupState) { + if info.transmissionLeft == 0 { + return } // As per RFC 2236 section 3 page 5 (for IGMPv2), @@ -490,36 +440,17 @@ func (g *GenericMulticastProtocolState) maybeSendInitialReportLocked(groupAddres sent, err := g.opts.Protocol.SendReport(groupAddress) if err == nil && sent { info.lastToSendReport = true - g.setDelayTimerForAddressRLocked(groupAddress, info, g.opts.MaxUnsolicitedReportDelay) - } -} -// maybeSendDelayedReportLocked attempts to send the delayed report. -// -// Host must be in pending, delaying or queued delaying member state. -// -// Precondition: g.protocolMU must be locked. -func (g *GenericMulticastProtocolState) maybeSendDelayedReportLocked(groupAddress tcpip.Address, info *multicastGroupState) { - if !info.state.isDelayingMember() { - panic(fmt.Sprintf("host must be in delaying or queued delaying member state to send delayed reports; group = %s, state = %d", groupAddress, info.state)) - } - - sent, err := g.opts.Protocol.SendReport(groupAddress) - if err == nil && sent { - info.lastToSendReport = true - info.state = idleMember - } else { - info.state = queuedDelayingMember + info.transmissionLeft-- + if info.transmissionLeft > 0 { + g.setDelayTimerForAddressLocked(groupAddress, info, g.opts.MaxUnsolicitedReportDelay) + } } } // maybeSendLeave attempts to send a leave message. func (g *GenericMulticastProtocolState) maybeSendLeave(groupAddress tcpip.Address, lastToSendReport bool) { - if !g.opts.Protocol.Enabled() || !lastToSendReport { - return - } - - if !g.opts.Protocol.ShouldPerformProtocol(groupAddress) { + if !g.shouldPerformForGroup(groupAddress) || !lastToSendReport { return } @@ -578,31 +509,30 @@ func (g *GenericMulticastProtocolState) maybeSendLeave(groupAddress tcpip.Addres // // Precondition: g.protocolMU must be locked. func (g *GenericMulticastProtocolState) transitionToNonMemberLocked(groupAddress tcpip.Address, info *multicastGroupState) { - if info.state == nonMember { + if !g.shouldPerformForGroup(groupAddress) { return } info.cancelDelayedReportJob() g.maybeSendLeave(groupAddress, info.lastToSendReport) info.lastToSendReport = false - info.state = nonMember } -// setDelayTimerForAddressRLocked sets timer to send a delay report. +// setDelayTimerForAddressLocked sets timer to send a delayed report. // -// Precondition: g.protocolMU MUST be read locked. -func (g *GenericMulticastProtocolState) setDelayTimerForAddressRLocked(groupAddress tcpip.Address, info *multicastGroupState, maxResponseTime time.Duration) { - if info.state == nonMember { +// Precondition: g.protocolMU MUST be locked. +func (g *GenericMulticastProtocolState) setDelayTimerForAddressLocked(groupAddress tcpip.Address, info *multicastGroupState, maxResponseTime time.Duration) { + if !g.shouldPerformForGroup(groupAddress) { return } - if !g.opts.Protocol.ShouldPerformProtocol(groupAddress) { - return + if info.transmissionLeft < minQueryResponseTransmissionCount { + info.transmissionLeft = minQueryResponseTransmissionCount } // As per RFC 2236 section 3 page 3 (for IGMPv2), // - // If a timer for the group is already unning, it is reset to the random + // If a timer for the group is already running, it is reset to the random // value only if the requested Max Response Time is less than the remaining // value of the running timer. // @@ -612,21 +542,14 @@ func (g *GenericMulticastProtocolState) setDelayTimerForAddressRLocked(groupAddr // random value only if the requested Maximum Response Delay is less than // the remaining value of the running timer. now := g.opts.Clock.Now() - if info.state == delayingMember { - if info.delayedReportJobFiresAt.IsZero() { - panic(fmt.Sprintf("delayed report unscheduled while in the delaying member state; group = %s", groupAddress)) - } - - if info.delayedReportJobFiresAt.Sub(now) <= maxResponseTime { - // The timer is scheduled to fire before the maximum response time so we - // leave our timer as is. - return - } + if !info.delayedReportJobFiresAt.IsZero() && info.delayedReportJobFiresAt.Sub(now) <= maxResponseTime { + // The timer is scheduled to fire before the maximum response time so we + // leave our timer as is. + return } - info.state = delayingMember - info.cancelDelayedReportJob() maxResponseTime = g.calculateDelayTimerDuration(maxResponseTime) + info.delayedReportJob.Cancel() info.delayedReportJob.Schedule(maxResponseTime) info.delayedReportJobFiresAt = now.Add(maxResponseTime) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast/route_table.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast/route_table.go index 41227e6ed..5bade5ae7 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast/route_table.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast/route_table.go @@ -116,7 +116,7 @@ func (r *InstalledRoute) SetLastUsedTimestamp(monotonicTime tcpip.MonotonicTime) // for the entry. For such routes, packets are added to an expiring queue until // a route is installed. type PendingRoute struct { - packets []*stack.PacketBuffer + packets []stack.PacketBufferPtr // expiration is the timestamp at which the pending route should be expired. // @@ -265,7 +265,7 @@ func (r *RouteTable) cleanupPendingRoutes() { func (r *RouteTable) newPendingRoute() PendingRoute { return PendingRoute{ - packets: make([]*stack.PacketBuffer, 0, r.config.MaxPendingQueueSize), + packets: make([]stack.PacketBufferPtr, 0, r.config.MaxPendingQueueSize), expiration: r.config.Clock.NowMonotonic().Add(DefaultPendingRouteExpiration), } } @@ -326,7 +326,7 @@ func (e GetRouteResultState) String() string { // // If the relevant pending route queue is at max capacity, then returns false. // Otherwise, returns true. -func (r *RouteTable) GetRouteOrInsertPending(key stack.UnicastSourceAndMulticastDestination, pkt *stack.PacketBuffer) (GetRouteResult, bool) { +func (r *RouteTable) GetRouteOrInsertPending(key stack.UnicastSourceAndMulticastDestination, pkt stack.PacketBufferPtr) (GetRouteResult, bool) { r.installedMu.RLock() defer r.installedMu.RUnlock() @@ -374,7 +374,7 @@ func (r *RouteTable) getOrCreatePendingRouteRLocked(key stack.UnicastSourceAndMu // returned. The caller assumes ownership of these packets and is responsible // for forwarding and releasing them. If an installed route already exists for // the provided key, then it is overwritten. -func (r *RouteTable) AddInstalledRoute(key stack.UnicastSourceAndMulticastDestination, route *InstalledRoute) []*stack.PacketBuffer { +func (r *RouteTable) AddInstalledRoute(key stack.UnicastSourceAndMulticastDestination, route *InstalledRoute) []stack.PacketBufferPtr { r.installedMu.Lock() defer r.installedMu.Unlock() r.installedRoutes[key] = route diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/icmp.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/icmp.go index e26079d68..7823f991a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/icmp.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/icmp.go @@ -19,6 +19,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/header/parse" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -137,7 +138,7 @@ func (e *endpoint) checkLocalAddress(addr tcpip.Address) bool { // of the original packet that caused the ICMP one to be sent. This information // is used to find out which transport endpoint must be notified about the ICMP // packet. We only expect the payload, not the enclosing ICMP packet. -func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.PacketBuffer) { +func (e *endpoint) handleControl(errInfo stack.TransportError, pkt stack.PacketBufferPtr) { h, ok := pkt.Data().PullUp(header.IPv4MinimumSize) if !ok { return @@ -174,7 +175,7 @@ func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.Packet e.dispatcher.DeliverTransportError(srcAddr, dstAddr, ProtocolNumber, p, errInfo, pkt) } -func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { +func (e *endpoint) handleICMP(pkt stack.PacketBufferPtr) { received := e.stats.icmp.packetsReceived h := header.ICMPv4(pkt.TransportHeader().Slice()) if len(h) < header.ICMPv4MinimumSize { @@ -183,7 +184,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { } // Only do in-stack processing if the checksum is correct. - if header.Checksum(h, pkt.Data().AsRange().Checksum()) != 0xffff { + if checksum.Checksum(h, pkt.Data().Checksum()) != 0xffff { received.invalid.Increment() // It's possible that a raw socket expects to receive this regardless // of checksum errors. If it's an echo request we know it's safe because @@ -255,7 +256,8 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { // It's possible that a raw socket expects to receive this. e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt) - pkt = nil + pkt = stack.PacketBufferPtr{} + _ = pkt // Suppress unused variable warning. sent := e.stats.icmp.packetsSent if !e.protocol.allowICMPReply(header.ICMPv4EchoReply, header.ICMPv4UnusedCode) { @@ -323,7 +325,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { replyICMPHdr := header.ICMPv4(replyData.AsSlice()) replyICMPHdr.SetType(header.ICMPv4EchoReply) replyICMPHdr.SetChecksum(0) - replyICMPHdr.SetChecksum(^header.Checksum(replyData.AsSlice(), 0)) + replyICMPHdr.SetChecksum(^checksum.Checksum(replyData.AsSlice(), 0)) replyBuf := bufferv2.MakeWithView(replyIPHdrView) replyBuf.Append(replyData.Clone()) @@ -483,7 +485,7 @@ func (*icmpReasonHostUnreachable) isICMPReason() {} // the problematic packet. It incorporates as much of that packet as // possible as well as any error metadata as is available. returnError // expects pkt to hold a valid IPv4 packet as per the wire format. -func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliveredLocally bool) tcpip.Error { +func (p *protocol) returnError(reason icmpReason, pkt stack.PacketBufferPtr, deliveredLocally bool) tcpip.Error { origIPHdr := header.IPv4(pkt.NetworkHeader().Slice()) origIPHdrSrc := origIPHdr.SourceAddress() origIPHdrDst := origIPHdr.DestinationAddress() @@ -665,7 +667,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv icmpHdr.SetCode(icmpCode) icmpHdr.SetType(icmpType) icmpHdr.SetPointer(pointer) - icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().AsRange().Checksum())) + icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().Checksum())) if err := route.WritePacket( stack.NetworkHeaderParams{ @@ -683,7 +685,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv } // OnReassemblyTimeout implements fragmentation.TimeoutHandler. -func (p *protocol) OnReassemblyTimeout(pkt *stack.PacketBuffer) { +func (p *protocol) OnReassemblyTimeout(pkt stack.PacketBufferPtr) { // OnReassemblyTimeout sends a Time Exceeded Message, as per RFC 792: // // If a host reassembling a fragmented datagram cannot complete the @@ -692,7 +694,7 @@ func (p *protocol) OnReassemblyTimeout(pkt *stack.PacketBuffer) { // // If fragment zero is not available then no time exceeded need be sent at // all. - if pkt != nil { + if !pkt.IsNil() { p.returnError(&icmpReasonReassemblyTimeout{}, pkt, true /* deliveredLocally */) } } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/igmp.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/igmp.go index 55dfe7761..bf338ea5e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/igmp.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/igmp.go @@ -186,7 +186,7 @@ func (igmp *igmpState) isSourceIPValidLocked(src tcpip.Address, messageType head } // +checklocks:igmp.ep.mu -func (igmp *igmpState) isPacketValidLocked(pkt *stack.PacketBuffer, messageType header.IGMPType, hasRouterAlertOption bool) bool { +func (igmp *igmpState) isPacketValidLocked(pkt stack.PacketBufferPtr, messageType header.IGMPType, hasRouterAlertOption bool) bool { // We can safely assume that the IP header is valid if we got this far. iph := header.IPv4(pkt.NetworkHeader().Slice()) @@ -204,7 +204,7 @@ func (igmp *igmpState) isPacketValidLocked(pkt *stack.PacketBuffer, messageType // handleIGMP handles an IGMP packet. // // +checklocks:igmp.ep.mu -func (igmp *igmpState) handleIGMP(pkt *stack.PacketBuffer, hasRouterAlertOption bool) { +func (igmp *igmpState) handleIGMP(pkt stack.PacketBufferPtr, hasRouterAlertOption bool) { received := igmp.ep.stats.igmp.packetsReceived hdr, ok := pkt.Data().PullUp(header.IGMPMinimumSize) if !ok { @@ -219,7 +219,7 @@ func (igmp *igmpState) handleIGMP(pkt *stack.PacketBuffer, hasRouterAlertOption // same set of octets, including the checksum field. If the result // is all 1 bits (-0 in 1's complement arithmetic), the check // succeeds. - if pkt.Data().AsRange().Checksum() != 0xFFFF { + if pkt.Data().Checksum() != 0xFFFF { received.checksumErrors.Increment() return } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/ipv4.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/ipv4.go index 4f245f7fe..c669b888d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/ipv4.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/network/ipv4/ipv4.go @@ -22,6 +22,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/atomicbitops" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -109,7 +110,7 @@ type endpoint struct { } // HandleLinkResolutionFailure implements stack.LinkResolvableNetworkEndpoint. -func (e *endpoint) HandleLinkResolutionFailure(pkt *stack.PacketBuffer) { +func (e *endpoint) HandleLinkResolutionFailure(pkt stack.PacketBufferPtr) { // If we are operating as a router, return an ICMP error to the original // packet's sender. if pkt.NetworkPacketInfo.IsForwardedPacket { @@ -409,7 +410,7 @@ func (e *endpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNumber { return e.protocol.Number() } -func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt *stack.PacketBuffer, params stack.NetworkHeaderParams, options header.IPv4OptionsSerializer) tcpip.Error { +func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt stack.PacketBufferPtr, params stack.NetworkHeaderParams, options header.IPv4OptionsSerializer) tcpip.Error { hdrLen := header.IPv4MinimumSize var optLen int if options != nil { @@ -447,7 +448,7 @@ func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt *stack.Packet // fragment. It returns the number of fragments handled and the number of // fragments left to be processed. The IP header must already be present in the // original packet. -func (e *endpoint) handleFragments(_ *stack.Route, networkMTU uint32, pkt *stack.PacketBuffer, handler func(*stack.PacketBuffer) tcpip.Error) (int, int, tcpip.Error) { +func (e *endpoint) handleFragments(_ *stack.Route, networkMTU uint32, pkt stack.PacketBufferPtr, handler func(stack.PacketBufferPtr) tcpip.Error) (int, int, tcpip.Error) { // Round the MTU down to align to 8 bytes. fragmentPayloadSize := networkMTU &^ 7 networkHeader := header.IPv4(pkt.NetworkHeader().Slice()) @@ -470,7 +471,7 @@ func (e *endpoint) handleFragments(_ *stack.Route, networkMTU uint32, pkt *stack } // WritePacket writes a packet to the given destination address and protocol. -func (e *endpoint) WritePacket(r *stack.Route, params stack.NetworkHeaderParams, pkt *stack.PacketBuffer) tcpip.Error { +func (e *endpoint) WritePacket(r *stack.Route, params stack.NetworkHeaderParams, pkt stack.PacketBufferPtr) tcpip.Error { if err := e.addIPHeader(r.LocalAddress(), r.RemoteAddress(), pkt, params, nil /* options */); err != nil { return err } @@ -478,7 +479,7 @@ func (e *endpoint) WritePacket(r *stack.Route, params stack.NetworkHeaderParams, return e.writePacket(r, pkt) } -func (e *endpoint) writePacket(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error { +func (e *endpoint) writePacket(r *stack.Route, pkt stack.PacketBufferPtr) tcpip.Error { netHeader := header.IPv4(pkt.NetworkHeader().Slice()) dstAddr := netHeader.DestinationAddress() @@ -510,7 +511,7 @@ func (e *endpoint) writePacket(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Er return e.writePacketPostRouting(r, pkt, false /* headerIncluded */) } -func (e *endpoint) writePacketPostRouting(r *stack.Route, pkt *stack.PacketBuffer, headerIncluded bool) tcpip.Error { +func (e *endpoint) writePacketPostRouting(r *stack.Route, pkt stack.PacketBufferPtr, headerIncluded bool) tcpip.Error { if r.Loop()&stack.PacketLoop != 0 { // If the packet was generated by the stack (not a raw/packet endpoint // where a packet may be written with the header included), then we can @@ -545,7 +546,7 @@ func (e *endpoint) writePacketPostRouting(r *stack.Route, pkt *stack.PacketBuffe // is set but the packet must be fragmented for the non-forwarding case. return &tcpip.ErrMessageTooLong{} } - sent, remain, err := e.handleFragments(r, networkMTU, pkt, func(fragPkt *stack.PacketBuffer) tcpip.Error { + sent, remain, err := e.handleFragments(r, networkMTU, pkt, func(fragPkt stack.PacketBufferPtr) tcpip.Error { // TODO(gvisor.dev/issue/3884): Evaluate whether we want to send each // fragment one by one using WritePacket() (current strategy) or if we // want to create a PacketBufferList from the fragments and feed it to @@ -566,7 +567,7 @@ func (e *endpoint) writePacketPostRouting(r *stack.Route, pkt *stack.PacketBuffe } // WriteHeaderIncludedPacket implements stack.NetworkEndpoint. -func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error { +func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt stack.PacketBufferPtr) tcpip.Error { // The packet already has an IP header, but there are a few required // checks. h, ok := pkt.Data().PullUp(header.IPv4MinimumSize) @@ -628,7 +629,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu // updating the options. // // This method should be invoked by the endpoint that received the pkt. -func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketBuffer, updateOptions bool) ip.ForwardingError { +func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt stack.PacketBufferPtr, updateOptions bool) ip.ForwardingError { h := header.IPv4(pkt.NetworkHeader().Slice()) stk := e.protocol.stack @@ -696,8 +697,10 @@ func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketB } // forwardUnicastPacket attempts to forward a packet to its final destination. -func (e *endpoint) forwardUnicastPacket(pkt *stack.PacketBuffer) ip.ForwardingError { - h := header.IPv4(pkt.NetworkHeader().Slice()) +func (e *endpoint) forwardUnicastPacket(pkt stack.PacketBufferPtr) ip.ForwardingError { + hView := pkt.NetworkHeader().View() + defer hView.Release() + h := header.IPv4(hView.AsSlice()) dstAddr := h.DestinationAddress() @@ -744,12 +747,14 @@ func (e *endpoint) forwardUnicastPacket(pkt *stack.PacketBuffer) ip.ForwardingEr r, err := stk.FindRoute(0, "", dstAddr, ProtocolNumber, false /* multicastLoop */) switch err.(type) { case nil: - case *tcpip.ErrNoRoute, *tcpip.ErrNetworkUnreachable: + // TODO(https://gvisor.dev/issues/8105): We should not observe ErrHostUnreachable from route + // lookups. + case *tcpip.ErrHostUnreachable, *tcpip.ErrNetworkUnreachable: // We return the original error rather than the result of returning // the ICMP packet because the original error is more relevant to // the caller. _ = e.protocol.returnError(&icmpReasonNetworkUnreachable{}, pkt, false /* deliveredLocally */) - return &ip.ErrNoRoute{} + return &ip.ErrHostUnreachable{} default: return &ip.ErrOther{Err: err} } @@ -770,7 +775,7 @@ func (e *endpoint) forwardUnicastPacket(pkt *stack.PacketBuffer) ip.ForwardingEr // HandlePacket is called by the link layer when new ipv4 packets arrive for // this endpoint. -func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { +func (e *endpoint) HandlePacket(pkt stack.PacketBufferPtr) { stats := e.stats.ip stats.PacketsReceived.Increment() @@ -780,11 +785,13 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { return } - h, ok := e.protocol.parseAndValidate(pkt) + hView, ok := e.protocol.parseAndValidate(pkt) if !ok { stats.MalformedPacketsReceived.Increment() return } + h := header.IPv4(hView.AsSlice()) + defer hView.Release() if !e.nic.IsLoopback() { if !e.protocol.options.AllowExternalLoopbackTraffic { @@ -827,19 +834,21 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { // handleLocalPacket is like HandlePacket except it does not perform the // prerouting iptables hook or check for loopback traffic that originated from // outside of the netstack (i.e. martian loopback packets). -func (e *endpoint) handleLocalPacket(pkt *stack.PacketBuffer, canSkipRXChecksum bool) { +func (e *endpoint) handleLocalPacket(pkt stack.PacketBufferPtr, canSkipRXChecksum bool) { stats := e.stats.ip stats.PacketsReceived.Increment() pkt = pkt.CloneToInbound() defer pkt.DecRef() - pkt.RXTransportChecksumValidated = canSkipRXChecksum + pkt.RXChecksumValidated = canSkipRXChecksum - h, ok := e.protocol.parseAndValidate(pkt) + hView, ok := e.protocol.parseAndValidate(pkt) if !ok { stats.MalformedPacketsReceived.Increment() return } + h := header.IPv4(hView.AsSlice()) + defer hView.Release() e.handleValidatedPacket(h, pkt, e.nic.Name() /* inNICName */) } @@ -868,7 +877,7 @@ func validateAddressesForForwarding(h header.IPv4) ip.ForwardingError { // // This method should be invoked for incoming multicast packets using the // endpoint that received the packet. -func (e *endpoint) forwardMulticastPacket(h header.IPv4, pkt *stack.PacketBuffer) ip.ForwardingError { +func (e *endpoint) forwardMulticastPacket(h header.IPv4, pkt stack.PacketBufferPtr) ip.ForwardingError { if err := validateAddressesForForwarding(h); err != nil { return err } @@ -918,10 +927,10 @@ func (e *endpoint) forwardMulticastPacket(h header.IPv4, pkt *stack.PacketBuffer default: panic(fmt.Sprintf("unexpected GetRouteResultState: %s", result.GetRouteResultState)) } - return &ip.ErrNoRoute{} + return &ip.ErrHostUnreachable{} } -func (e *endpoint) updateOptionsForForwarding(pkt *stack.PacketBuffer) ip.ForwardingError { +func (e *endpoint) updateOptionsForForwarding(pkt stack.PacketBufferPtr) ip.ForwardingError { h := header.IPv4(pkt.NetworkHeader().Slice()) if opts := h.Options(); len(opts) != 0 { newOpts, _, optProblem := e.processIPOptions(pkt, opts, &optionUsageForward{}) @@ -956,7 +965,7 @@ func (e *endpoint) updateOptionsForForwarding(pkt *stack.PacketBuffer) ip.Forwar // provided installedRoute. // // This method should be invoked by the endpoint that received the pkt. -func (e *endpoint) forwardValidatedMulticastPacket(pkt *stack.PacketBuffer, installedRoute *multicast.InstalledRoute) ip.ForwardingError { +func (e *endpoint) forwardValidatedMulticastPacket(pkt stack.PacketBufferPtr, installedRoute *multicast.InstalledRoute) ip.ForwardingError { // Per RFC 1812 section 5.2.1.3, // // Based on the IP source and destination addresses found in the datagram @@ -989,7 +998,7 @@ func (e *endpoint) forwardValidatedMulticastPacket(pkt *stack.PacketBuffer, inst // of the provided outgoingInterface. // // This method should be invoked by the endpoint that received the pkt. -func (e *endpoint) forwardMulticastPacketForOutgoingInterface(pkt *stack.PacketBuffer, outgoingInterface stack.MulticastRouteOutgoingInterface) ip.ForwardingError { +func (e *endpoint) forwardMulticastPacketForOutgoingInterface(pkt stack.PacketBufferPtr, outgoingInterface stack.MulticastRouteOutgoingInterface) ip.ForwardingError { h := header.IPv4(pkt.NetworkHeader().Slice()) // Per RFC 1812 section 5.2.1.3, @@ -1009,14 +1018,14 @@ func (e *endpoint) forwardMulticastPacketForOutgoingInterface(pkt *stack.PacketB if route == nil { // Failed to convert to a stack.Route. This likely means that the outgoing // endpoint no longer exists. - return &ip.ErrNoRoute{} + return &ip.ErrHostUnreachable{} } defer route.Release() return e.forwardPacketWithRoute(route, pkt, true /* updateOptions */) } -func (e *endpoint) handleValidatedPacket(h header.IPv4, pkt *stack.PacketBuffer, inNICName string) { +func (e *endpoint) handleValidatedPacket(h header.IPv4, pkt stack.PacketBufferPtr, inNICName string) { pkt.NICID = e.nic.ID() // Raw socket packets are delivered based solely on the transport protocol @@ -1105,7 +1114,7 @@ func (e *endpoint) handleForwardingError(err ip.ForwardingError) { stats.Forwarding.LinkLocalDestination.Increment() case *ip.ErrTTLExceeded: stats.Forwarding.ExhaustedTTL.Increment() - case *ip.ErrNoRoute: + case *ip.ErrHostUnreachable: stats.Forwarding.Unrouteable.Increment() case *ip.ErrParameterProblem: stats.MalformedPacketsReceived.Increment() @@ -1123,7 +1132,7 @@ func (e *endpoint) handleForwardingError(err ip.ForwardingError) { stats.Forwarding.Errors.Increment() } -func (e *endpoint) deliverPacketLocally(h header.IPv4, pkt *stack.PacketBuffer, inNICName string) { +func (e *endpoint) deliverPacketLocally(h header.IPv4, pkt stack.PacketBufferPtr, inNICName string) { stats := e.stats // iptables filtering. All packets that reach here are intended for // this machine and will not be forwarded. @@ -1583,7 +1592,7 @@ func (p *protocol) RemoveMulticastRoute(addresses stack.UnicastSourceAndMulticas } if removed := p.multicastRouteTable.RemoveInstalledRoute(addresses); !removed { - return &tcpip.ErrNoRoute{} + return &tcpip.ErrHostUnreachable{} } return nil @@ -1627,13 +1636,13 @@ func (p *protocol) MulticastRouteLastUsedTime(addresses stack.UnicastSourceAndMu timestamp, found := p.multicastRouteTable.GetLastUsedTimestamp(addresses) if !found { - return tcpip.MonotonicTime{}, &tcpip.ErrNoRoute{} + return tcpip.MonotonicTime{}, &tcpip.ErrHostUnreachable{} } return timestamp, nil } -func (p *protocol) forwardPendingMulticastPacket(pkt *stack.PacketBuffer, installedRoute *multicast.InstalledRoute) { +func (p *protocol) forwardPendingMulticastPacket(pkt stack.PacketBufferPtr, installedRoute *multicast.InstalledRoute) { defer pkt.DecRef() // Attempt to forward the packet using the endpoint that it originally @@ -1690,7 +1699,7 @@ func (p *protocol) isSubnetLocalBroadcastAddress(addr tcpip.Address) bool { // returns the parsed IP header. // // Returns true if the IP header was successfully parsed. -func (p *protocol) parseAndValidate(pkt *stack.PacketBuffer) (header.IPv4, bool) { +func (p *protocol) parseAndValidate(pkt stack.PacketBufferPtr) (*bufferv2.View, bool) { transProtoNum, hasTransportHdr, ok := p.Parse(pkt) if !ok { return nil, false @@ -1703,7 +1712,7 @@ func (p *protocol) parseAndValidate(pkt *stack.PacketBuffer) (header.IPv4, bool) return nil, false } - if !h.IsChecksumValid() { + if !pkt.RXChecksumValidated && !h.IsChecksumValid() { return nil, false } @@ -1711,10 +1720,10 @@ func (p *protocol) parseAndValidate(pkt *stack.PacketBuffer) (header.IPv4, bool) p.parseTransport(pkt, transProtoNum) } - return h, true + return pkt.NetworkHeader().View(), true } -func (p *protocol) parseTransport(pkt *stack.PacketBuffer, transProtoNum tcpip.TransportProtocolNumber) { +func (p *protocol) parseTransport(pkt stack.PacketBufferPtr, transProtoNum tcpip.TransportProtocolNumber) { if transProtoNum == header.ICMPv4ProtocolNumber { // The transport layer will handle transport layer parsing errors. _ = parse.ICMPv4(pkt) @@ -1732,7 +1741,7 @@ func (p *protocol) parseTransport(pkt *stack.PacketBuffer, transProtoNum tcpip.T } // Parse implements stack.NetworkProtocol. -func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) { +func (*protocol) Parse(pkt stack.PacketBufferPtr) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) { if ok := parse.IPv4(pkt); !ok { return 0, false, false } @@ -1759,7 +1768,7 @@ func (p *protocol) allowICMPReply(icmpType header.ICMPv4Type, code header.ICMPv4 } // SendRejectionError implements stack.RejectIPv4WithHandler. -func (p *protocol) SendRejectionError(pkt *stack.PacketBuffer, rejectWith stack.RejectIPv4WithICMPType, inputHook bool) tcpip.Error { +func (p *protocol) SendRejectionError(pkt stack.PacketBufferPtr, rejectWith stack.RejectIPv4WithICMPType, inputHook bool) tcpip.Error { switch rejectWith { case stack.RejectIPv4WithICMPNetUnreachable: return p.returnError(&icmpReasonNetworkUnreachable{}, pkt, inputHook) @@ -1801,7 +1810,7 @@ func calculateNetworkMTU(linkMTU, networkHeaderSize uint32) (uint32, tcpip.Error return networkMTU - networkHeaderSize, nil } -func packetMustBeFragmented(pkt *stack.PacketBuffer, networkMTU uint32) bool { +func packetMustBeFragmented(pkt stack.PacketBufferPtr, networkMTU uint32) bool { payload := len(pkt.TransportHeader().Slice()) + pkt.Data().Size() return pkt.GSOOptions.Type == stack.GSONone && uint32(payload) > networkMTU } @@ -1877,7 +1886,7 @@ func NewProtocol(s *stack.Stack) stack.NetworkProtocol { return NewProtocolWithOptions(Options{})(s) } -func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeader header.IPv4) (*stack.PacketBuffer, bool) { +func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeader header.IPv4) (stack.PacketBufferPtr, bool) { fragPkt, offset, copied, more := pf.BuildNextFragment() fragPkt.NetworkProtocolNumber = ProtocolNumber @@ -2218,7 +2227,7 @@ type optionTracker struct { // // If there were no errors during parsing, the new set of options is returned as // a new buffer. -func (e *endpoint) processIPOptions(pkt *stack.PacketBuffer, opts header.IPv4Options, usage optionsUsage) (header.IPv4Options, optionTracker, *header.IPv4OptParameterProblem) { +func (e *endpoint) processIPOptions(pkt stack.PacketBufferPtr, opts header.IPv4Options, usage optionsUsage) (header.IPv4Options, optionTracker, *header.IPv4OptParameterProblem) { stats := e.stats.ip optIter := opts.MakeIterator() diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/socketops.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/socketops.go index b7dbe45c8..28d04ba26 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/socketops.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/socketops.go @@ -116,7 +116,7 @@ func (*DefaultSocketOptionsHandler) OnSetReceiveBufferSize(v, oldSz int64) (newS // implemented by the stack. type StackHandler interface { // Option allows retrieving stack wide options. - Option(option interface{}) Error + Option(option any) Error // TransportProtocolOption allows retrieving individual protocol level // option values. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_mutex.go new file mode 100644 index 000000000..a0177a582 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type addressStateRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var addressStatelockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type addressStatelockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *addressStateRWMutex) Lock() { + locking.AddGLock(addressStateprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *addressStateRWMutex) NestedLock(i addressStatelockNameIndex) { + locking.AddGLock(addressStateprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *addressStateRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(addressStateprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *addressStateRWMutex) NestedUnlock(i addressStatelockNameIndex) { + m.mu.Unlock() + locking.DelGLock(addressStateprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *addressStateRWMutex) RLock() { + locking.AddGLock(addressStateprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *addressStateRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(addressStateprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *addressStateRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *addressStateRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *addressStateRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var addressStateprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func addressStateinitLockNames() {} + +func init() { + addressStateinitLockNames() + addressStateprefixIndex = locking.NewMutexClass(reflect.TypeOf(addressStateRWMutex{}), addressStatelockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_refs.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_refs.go new file mode 100644 index 000000000..fadbf04a8 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/address_state_refs.go @@ -0,0 +1,140 @@ +package stack + +import ( + "fmt" + + "gvisor.dev/gvisor/pkg/atomicbitops" + "gvisor.dev/gvisor/pkg/refs" +) + +// enableLogging indicates whether reference-related events should be logged (with +// stack traces). This is false by default and should only be set to true for +// debugging purposes, as it can generate an extremely large amount of output +// and drastically degrade performance. +const addressStateenableLogging = false + +// obj is used to customize logging. Note that we use a pointer to T so that +// we do not copy the entire object when passed as a format parameter. +var addressStateobj *addressState + +// Refs implements refs.RefCounter. It keeps a reference count using atomic +// operations and calls the destructor when the count reaches zero. +// +// NOTE: Do not introduce additional fields to the Refs struct. It is used by +// many filesystem objects, and we want to keep it as small as possible (i.e., +// the same size as using an int64 directly) to avoid taking up extra cache +// space. In general, this template should not be extended at the cost of +// performance. If it does not offer enough flexibility for a particular object +// (example: b/187877947), we should implement the RefCounter/CheckedObject +// interfaces manually. +// +// +stateify savable +type addressStateRefs struct { + // refCount is composed of two fields: + // + // [32-bit speculative references]:[32-bit real references] + // + // Speculative references are used for TryIncRef, to avoid a CompareAndSwap + // loop. See IncRef, DecRef and TryIncRef for details of how these fields are + // used. + refCount atomicbitops.Int64 +} + +// InitRefs initializes r with one reference and, if enabled, activates leak +// checking. +func (r *addressStateRefs) InitRefs() { + r.refCount.Store(1) + refs.Register(r) +} + +// RefType implements refs.CheckedObject.RefType. +func (r *addressStateRefs) RefType() string { + return fmt.Sprintf("%T", addressStateobj)[1:] +} + +// LeakMessage implements refs.CheckedObject.LeakMessage. +func (r *addressStateRefs) LeakMessage() string { + return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) +} + +// LogRefs implements refs.CheckedObject.LogRefs. +func (r *addressStateRefs) LogRefs() bool { + return addressStateenableLogging +} + +// ReadRefs returns the current number of references. The returned count is +// inherently racy and is unsafe to use without external synchronization. +func (r *addressStateRefs) ReadRefs() int64 { + return r.refCount.Load() +} + +// IncRef implements refs.RefCounter.IncRef. +// +//go:nosplit +func (r *addressStateRefs) IncRef() { + v := r.refCount.Add(1) + if addressStateenableLogging { + refs.LogIncRef(r, v) + } + if v <= 1 { + panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) + } +} + +// TryIncRef implements refs.TryRefCounter.TryIncRef. +// +// To do this safely without a loop, a speculative reference is first acquired +// on the object. This allows multiple concurrent TryIncRef calls to distinguish +// other TryIncRef calls from genuine references held. +// +//go:nosplit +func (r *addressStateRefs) TryIncRef() bool { + const speculativeRef = 1 << 32 + if v := r.refCount.Add(speculativeRef); int32(v) == 0 { + + r.refCount.Add(-speculativeRef) + return false + } + + v := r.refCount.Add(-speculativeRef + 1) + if addressStateenableLogging { + refs.LogTryIncRef(r, v) + } + return true +} + +// DecRef implements refs.RefCounter.DecRef. +// +// Note that speculative references are counted here. Since they were added +// prior to real references reaching zero, they will successfully convert to +// real references. In other words, we see speculative references only in the +// following case: +// +// A: TryIncRef [speculative increase => sees non-negative references] +// B: DecRef [real decrease] +// A: TryIncRef [transform speculative to real] +// +//go:nosplit +func (r *addressStateRefs) DecRef(destroy func()) { + v := r.refCount.Add(-1) + if addressStateenableLogging { + refs.LogDecRef(r, v) + } + switch { + case v < 0: + panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) + + case v == 0: + refs.Unregister(r) + + if destroy != nil { + destroy() + } + } +} + +func (r *addressStateRefs) afterLoad() { + if r.ReadRefs() > 0 { + refs.Register(r) + } +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state.go index df9953375..91b615eb6 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state.go @@ -17,7 +17,6 @@ package stack import ( "fmt" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" ) @@ -38,7 +37,7 @@ type AddressableEndpointState struct { // // AddressableEndpointState.mu // addressState.mu - mu sync.RWMutex + mu addressableEndpointStateRWMutex // +checklocks:mu endpoints map[tcpip.Address]*addressState // +checklocks:mu @@ -223,7 +222,7 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address } addrState.mu.RLock() - if addrState.refs == 0 { + if addrState.refs.ReadRefs() == 0 { panic(fmt.Sprintf("found an address that should have been released (ref count == 0); address = %s", addrState.addr)) } isPermanent := addrState.kind.IsPermanent() @@ -257,6 +256,7 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address break } } + addrState.refs.IncRef() } else { addrState = &addressState{ addressableEndpointState: a, @@ -266,11 +266,11 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address // results in allocations on every call. subnet: addr.Subnet(), } + addrState.refs.InitRefs() a.endpoints[addr.Address] = addrState // We never promote an address to temporary - it can only be added as such. // If we are actually adding a permanent address, it is promoted below. addrState.kind = Temporary - addrState.disp = properties.Disp } // At this point we have an address we are either promoting from an expired or @@ -287,15 +287,14 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address } // Primary addresses are biased by 1. - addrState.refs++ + addrState.refs.IncRef() addrState.kind = kind } - // Acquire the address before returning it. - addrState.refs++ addrState.configType = properties.ConfigType lifetimes := properties.Lifetimes lifetimes.sanitize() addrState.lifetimes = lifetimes + addrState.disp = properties.Disp if attemptAddToPrimary { switch properties.PEB { @@ -384,19 +383,16 @@ func (a *AddressableEndpointState) decAddressRef(addrState *addressState) { // // +checklocks:a.mu func (a *AddressableEndpointState) decAddressRefLocked(addrState *addressState) { - addrState.mu.Lock() - defer addrState.mu.Unlock() - - if addrState.refs == 0 { - panic(fmt.Sprintf("attempted to decrease ref count for AddressEndpoint w/ addr = %s when it is already released", addrState.addr)) - } - - addrState.refs-- + destroy := false + addrState.refs.DecRef(func() { + destroy = true + }) - if addrState.refs != 0 { + if !destroy { return } - + addrState.mu.Lock() + defer addrState.mu.Unlock() // A non-expired permanent address must not have its reference count dropped // to 0. if addrState.kind.IsPermanent() { @@ -701,9 +697,8 @@ type addressState struct { // // AddressableEndpointState.mu // addressState.mu - mu sync.RWMutex - // checklocks:mu - refs uint32 + mu addressStateRWMutex + refs addressStateRefs // checklocks:mu kind AddressKind // checklocks:mu @@ -788,14 +783,7 @@ func (a *addressState) IsAssigned(allowExpired bool) bool { // IncRef implements AddressEndpoint. func (a *addressState) IncRef() bool { - a.mu.Lock() - defer a.mu.Unlock() - if a.refs == 0 { - return false - } - - a.refs++ - return true + return a.refs.TryIncRef() } // DecRef implements AddressEndpoint. @@ -809,13 +797,9 @@ func (a *addressState) DecRef() { // Panics if the ref count is less than 2 after acquiring the lock in this // function. func (a *addressState) decRefMustNotFree() { - a.mu.Lock() - defer a.mu.Unlock() - - if a.refs < 2 { - panic(fmt.Sprintf("cannot decrease addressState %s ref count %d without freeing the endpoint", a.addr, a.refs)) - } - a.refs-- + a.refs.DecRef(func() { + panic(fmt.Sprintf("cannot decrease addressState %s without freeing the endpoint", a.addr)) + }) } // ConfigType implements AddressEndpoint. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state_mutex.go new file mode 100644 index 000000000..f78028d67 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/addressable_endpoint_state_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type addressableEndpointStateRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var addressableEndpointStatelockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type addressableEndpointStatelockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) Lock() { + locking.AddGLock(addressableEndpointStateprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) NestedLock(i addressableEndpointStatelockNameIndex) { + locking.AddGLock(addressableEndpointStateprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(addressableEndpointStateprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) NestedUnlock(i addressableEndpointStatelockNameIndex) { + m.mu.Unlock() + locking.DelGLock(addressableEndpointStateprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) RLock() { + locking.AddGLock(addressableEndpointStateprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(addressableEndpointStateprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *addressableEndpointStateRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var addressableEndpointStateprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func addressableEndpointStateinitLockNames() {} + +func init() { + addressableEndpointStateinitLockNames() + addressableEndpointStateprefixIndex = locking.NewMutexClass(reflect.TypeOf(addressableEndpointStateRWMutex{}), addressableEndpointStatelockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/bucket_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/bucket_mutex.go new file mode 100644 index 000000000..e4100b1e7 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/bucket_mutex.go @@ -0,0 +1,98 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type bucketRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var bucketlockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type bucketlockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +const ( + bucketLockOthertuple = bucketlockNameIndex(0) +) +const () + +// Lock locks m. +// +checklocksignore +func (m *bucketRWMutex) Lock() { + locking.AddGLock(bucketprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *bucketRWMutex) NestedLock(i bucketlockNameIndex) { + locking.AddGLock(bucketprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *bucketRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(bucketprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *bucketRWMutex) NestedUnlock(i bucketlockNameIndex) { + m.mu.Unlock() + locking.DelGLock(bucketprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *bucketRWMutex) RLock() { + locking.AddGLock(bucketprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *bucketRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(bucketprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *bucketRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *bucketRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *bucketRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var bucketprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func bucketinitLockNames() { bucketlockNames = []string{"otherTuple"} } + +func init() { + bucketinitLockNames() + bucketprefixIndex = locking.NewMutexClass(reflect.TypeOf(bucketRWMutex{}), bucketlockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/cleanup_endpoints_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/cleanup_endpoints_mutex.go new file mode 100644 index 000000000..0270b25db --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/cleanup_endpoints_mutex.go @@ -0,0 +1,64 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// Mutex is sync.Mutex with the correctness validator. +type cleanupEndpointsMutex struct { + mu sync.Mutex +} + +var cleanupEndpointsprefixIndex *locking.MutexClass + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var cleanupEndpointslockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type cleanupEndpointslockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *cleanupEndpointsMutex) Lock() { + locking.AddGLock(cleanupEndpointsprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *cleanupEndpointsMutex) NestedLock(i cleanupEndpointslockNameIndex) { + locking.AddGLock(cleanupEndpointsprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *cleanupEndpointsMutex) Unlock() { + locking.DelGLock(cleanupEndpointsprefixIndex, -1) + m.mu.Unlock() +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *cleanupEndpointsMutex) NestedUnlock(i cleanupEndpointslockNameIndex) { + locking.DelGLock(cleanupEndpointsprefixIndex, int(i)) + m.mu.Unlock() +} + +// DO NOT REMOVE: The following function is automatically replaced. +func cleanupEndpointsinitLockNames() {} + +func init() { + cleanupEndpointsinitLockNames() + cleanupEndpointsprefixIndex = locking.NewMutexClass(reflect.TypeOf(cleanupEndpointsMutex{}), cleanupEndpointslockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_mutex.go new file mode 100644 index 000000000..6af809e79 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type connRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var connlockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type connlockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *connRWMutex) Lock() { + locking.AddGLock(connprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *connRWMutex) NestedLock(i connlockNameIndex) { + locking.AddGLock(connprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *connRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(connprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *connRWMutex) NestedUnlock(i connlockNameIndex) { + m.mu.Unlock() + locking.DelGLock(connprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *connRWMutex) RLock() { + locking.AddGLock(connprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *connRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(connprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *connRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *connRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *connRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var connprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func conninitLockNames() {} + +func init() { + conninitLockNames() + connprefixIndex = locking.NewMutexClass(reflect.TypeOf(connRWMutex{}), connlockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_track_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_track_mutex.go new file mode 100644 index 000000000..ad020f1ee --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conn_track_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type connTrackRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var connTracklockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type connTracklockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *connTrackRWMutex) Lock() { + locking.AddGLock(connTrackprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *connTrackRWMutex) NestedLock(i connTracklockNameIndex) { + locking.AddGLock(connTrackprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *connTrackRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(connTrackprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *connTrackRWMutex) NestedUnlock(i connTracklockNameIndex) { + m.mu.Unlock() + locking.DelGLock(connTrackprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *connTrackRWMutex) RLock() { + locking.AddGLock(connTrackprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *connTrackRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(connTrackprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *connTrackRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *connTrackRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *connTrackRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var connTrackprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func connTrackinitLockNames() {} + +func init() { + connTrackinitLockNames() + connTrackprefixIndex = locking.NewMutexClass(reflect.TypeOf(connTrackRWMutex{}), connTracklockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conntrack.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conntrack.go index 8bc091abf..95e11ac47 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conntrack.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/conntrack.go @@ -139,7 +139,7 @@ type conn struct { // Holds a finalizeResult. finalizeResult atomicbitops.Uint32 - mu sync.RWMutex `state:"nosave"` + mu connRWMutex `state:"nosave"` // sourceManip indicates the source manipulation type. // // +checklocks:mu @@ -149,7 +149,7 @@ type conn struct { // +checklocks:mu destinationManip manipType - stateMu sync.RWMutex `state:"nosave"` + stateMu stateConnRWMutex `state:"nosave"` // tcb is TCB control block. It is used to keep track of states // of tcp connection. // @@ -177,7 +177,7 @@ func (cn *conn) timedOut(now tcpip.MonotonicTime) bool { } // update the connection tracking state. -func (cn *conn) update(pkt *PacketBuffer, reply bool) { +func (cn *conn) update(pkt PacketBufferPtr, reply bool) { cn.stateMu.Lock() defer cn.stateMu.Unlock() @@ -230,7 +230,7 @@ type ConnTrack struct { clock tcpip.Clock rand *rand.Rand - mu sync.RWMutex `state:"nosave"` + mu connTrackRWMutex `state:"nosave"` // mu protects the buckets slice, but not buckets' contents. Only take // the write lock if you are modifying the slice or saving for S/R. // @@ -240,7 +240,7 @@ type ConnTrack struct { // +stateify savable type bucket struct { - mu sync.RWMutex `state:"nosave"` + mu bucketRWMutex `state:"nosave"` // +checklocks:mu tuples tupleList } @@ -269,7 +269,7 @@ func v6NetAndTransHdr(icmpPayload []byte, minTransHdrLen int) (header.Network, [ return netHdr, transHdr[:minTransHdrLen] } -func getEmbeddedNetAndTransHeaders(pkt *PacketBuffer, netHdrLength int, getNetAndTransHdr netAndTransHeadersFunc, transProto tcpip.TransportProtocolNumber) (header.Network, header.ChecksummableTransport, bool) { +func getEmbeddedNetAndTransHeaders(pkt PacketBufferPtr, netHdrLength int, getNetAndTransHdr netAndTransHeadersFunc, transProto tcpip.TransportProtocolNumber) (header.Network, header.ChecksummableTransport, bool) { switch transProto { case header.TCPProtocolNumber: if netAndTransHeader, ok := pkt.Data().PullUp(netHdrLength + header.TCPMinimumSize); ok { @@ -285,7 +285,7 @@ func getEmbeddedNetAndTransHeaders(pkt *PacketBuffer, netHdrLength int, getNetAn return nil, nil, false } -func getHeaders(pkt *PacketBuffer) (netHdr header.Network, transHdr header.Transport, isICMPError bool, ok bool) { +func getHeaders(pkt PacketBufferPtr) (netHdr header.Network, transHdr header.Transport, isICMPError bool, ok bool) { switch pkt.TransportProtocolNumber { case header.TCPProtocolNumber: if tcpHeader := header.TCP(pkt.TransportHeader().Slice()); len(tcpHeader) >= header.TCPMinimumSize { @@ -373,7 +373,7 @@ func getTupleIDForRegularPacket(netHdr header.Network, netProto tcpip.NetworkPro } } -func getTupleIDForPacketInICMPError(pkt *PacketBuffer, getNetAndTransHdr netAndTransHeadersFunc, netProto tcpip.NetworkProtocolNumber, netLen int, transProto tcpip.TransportProtocolNumber) (tupleID, bool) { +func getTupleIDForPacketInICMPError(pkt PacketBufferPtr, getNetAndTransHdr netAndTransHeadersFunc, netProto tcpip.NetworkProtocolNumber, netLen int, transProto tcpip.TransportProtocolNumber) (tupleID, bool) { if netHdr, transHdr, ok := getEmbeddedNetAndTransHeaders(pkt, netLen, getNetAndTransHdr, transProto); ok { return tupleID{ srcAddr: netHdr.DestinationAddress(), @@ -396,7 +396,7 @@ const ( getTupleIDOKAndDontAllowNewConn ) -func getTupleIDForEchoPacket(pkt *PacketBuffer, ident uint16, request bool) tupleID { +func getTupleIDForEchoPacket(pkt PacketBufferPtr, ident uint16, request bool) tupleID { netHdr := pkt.Network() tid := tupleID{ srcAddr: netHdr.SourceAddress(), @@ -414,7 +414,7 @@ func getTupleIDForEchoPacket(pkt *PacketBuffer, ident uint16, request bool) tupl return tid } -func getTupleID(pkt *PacketBuffer) (tupleID, getTupleIDDisposition) { +func getTupleID(pkt PacketBufferPtr) (tupleID, getTupleIDDisposition) { switch pkt.TransportProtocolNumber { case header.TCPProtocolNumber: if transHeader := header.TCP(pkt.TransportHeader().Slice()); len(transHeader) >= header.TCPMinimumSize { @@ -504,7 +504,7 @@ func (ct *ConnTrack) init() { // // If the packet's protocol is trackable, the connection's state is updated to // match the contents of the packet. -func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation bool) *tuple { +func (ct *ConnTrack) getConnAndUpdate(pkt PacketBufferPtr, skipChecksumValidation bool) *tuple { // Get or (maybe) create a connection. t := func() *tuple { var allowNewConn bool @@ -526,32 +526,30 @@ func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation case header.TCPProtocolNumber: _, csumValid, ok := header.TCPValid( header.TCP(pkt.TransportHeader().Slice()), - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), tid.srcAddr, tid.dstAddr, - pkt.RXTransportChecksumValidated || skipChecksumValidation) + pkt.RXChecksumValidated || skipChecksumValidation) if !csumValid || !ok { return nil } case header.UDPProtocolNumber: lengthValid, csumValid := header.UDPValid( header.UDP(pkt.TransportHeader().Slice()), - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, tid.srcAddr, tid.dstAddr, - pkt.RXTransportChecksumValidated || skipChecksumValidation) + pkt.RXChecksumValidated || skipChecksumValidation) if !lengthValid || !csumValid { return nil } } - bktID := ct.bucket(tid) - ct.mu.RLock() - bkt := &ct.buckets[bktID] + bkt := &ct.buckets[ct.bucket(tid)] ct.mu.RUnlock() now := ct.clock.NowMonotonic() @@ -603,10 +601,8 @@ func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation } func (ct *ConnTrack) connForTID(tid tupleID) *tuple { - bktID := ct.bucket(tid) - ct.mu.RLock() - bkt := &ct.buckets[bktID] + bkt := &ct.buckets[ct.bucket(tid)] ct.mu.RUnlock() return bkt.connForTID(tid, ct.clock.NowMonotonic()) @@ -635,7 +631,7 @@ func (ct *ConnTrack) finalize(cn *conn) finalizeResult { { tid := cn.reply.tupleID - id := ct.bucket(tid) + id := ct.bucketWithTableLength(tid, len(buckets)) bkt := &buckets[id] bkt.mu.Lock() @@ -663,7 +659,7 @@ func (ct *ConnTrack) finalize(cn *conn) finalizeResult { // better. tid := cn.original.tupleID - id := ct.bucket(tid) + id := ct.bucketWithTableLength(tid, len(buckets)) bkt := &buckets[id] bkt.mu.Lock() defer bkt.mu.Unlock() @@ -729,7 +725,7 @@ type portOrIdentRange struct { // // Generally, only the first packet of a connection reaches this method; other // packets will be manipulated without needing to modify the connection. -func (cn *conn) performNAT(pkt *PacketBuffer, hook Hook, r *Route, portsOrIdents portOrIdentRange, natAddress tcpip.Address, dnat bool) { +func (cn *conn) performNAT(pkt PacketBufferPtr, hook Hook, r *Route, portsOrIdents portOrIdentRange, natAddress tcpip.Address, dnat bool) { lastPortOrIdent := func() uint16 { lastPortOrIdent := uint32(portsOrIdents.start) + portsOrIdents.size - 1 if lastPortOrIdent > math.MaxUint16 { @@ -830,7 +826,7 @@ func (cn *conn) performNAT(pkt *PacketBuffer, hook Hook, r *Route, portsOrIdents // has had NAT performed on it. // // Returns true if the packet can skip the NAT table. -func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { +func (cn *conn) handlePacket(pkt PacketBufferPtr, hook Hook, rt *Route) bool { netHdr, transHdr, isICMPError, ok := getHeaders(pkt) if !ok { return false @@ -937,7 +933,7 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { icmp := header.ICMPv4(pkt.TransportHeader().Slice()) // TODO(https://gvisor.dev/issue/6788): Incrementally update ICMP checksum. icmp.SetChecksum(0) - icmp.SetChecksum(header.ICMPv4Checksum(icmp, pkt.Data().AsRange().Checksum())) + icmp.SetChecksum(header.ICMPv4Checksum(icmp, pkt.Data().Checksum())) network := header.IPv4(pkt.NetworkHeader().Slice()) if dnat { @@ -963,7 +959,7 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { Header: icmp, Src: srcAddr, Dst: dstAddr, - PayloadCsum: payload.AsRange().Checksum(), + PayloadCsum: payload.Checksum(), PayloadLen: payload.Size(), })) @@ -978,7 +974,12 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { } // bucket gets the conntrack bucket for a tupleID. +// +checklocksread:ct.mu func (ct *ConnTrack) bucket(id tupleID) int { + return ct.bucketWithTableLength(id, len(ct.buckets)) +} + +func (ct *ConnTrack) bucketWithTableLength(id tupleID, tableLength int) int { h := jenkins.Sum32(ct.seed) h.Write([]byte(id.srcAddr)) h.Write([]byte(id.dstAddr)) @@ -991,9 +992,7 @@ func (ct *ConnTrack) bucket(id tupleID) int { h.Write([]byte(shortBuf)) binary.LittleEndian.PutUint16(shortBuf, uint16(id.netProto)) h.Write([]byte(shortBuf)) - ct.mu.RLock() - defer ct.mu.RUnlock() - return int(h.Sum32()) % len(ct.buckets) + return int(h.Sum32()) % tableLength } // reapUnused deletes timed out entries from the conntrack map. The rules for @@ -1098,9 +1097,9 @@ func (ct *ConnTrack) reapTupleLocked(reapingTuple *tuple, bktID int, bkt *bucket bkt.tuples.Remove(otherTuple) } else { otherTupleBkt := &ct.buckets[otherTupleBktID] - otherTupleBkt.mu.Lock() + otherTupleBkt.mu.NestedLock(bucketLockOthertuple) otherTupleBkt.tuples.Remove(otherTuple) - otherTupleBkt.mu.Unlock() + otherTupleBkt.mu.NestedUnlock(bucketLockOthertuple) } return true diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/endpoints_by_nic_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/endpoints_by_nic_mutex.go new file mode 100644 index 000000000..ba1cd360a --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/endpoints_by_nic_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type endpointsByNICRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var endpointsByNIClockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type endpointsByNIClockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *endpointsByNICRWMutex) Lock() { + locking.AddGLock(endpointsByNICprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *endpointsByNICRWMutex) NestedLock(i endpointsByNIClockNameIndex) { + locking.AddGLock(endpointsByNICprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *endpointsByNICRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(endpointsByNICprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *endpointsByNICRWMutex) NestedUnlock(i endpointsByNIClockNameIndex) { + m.mu.Unlock() + locking.DelGLock(endpointsByNICprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *endpointsByNICRWMutex) RLock() { + locking.AddGLock(endpointsByNICprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *endpointsByNICRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(endpointsByNICprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *endpointsByNICRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *endpointsByNICRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *endpointsByNICRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var endpointsByNICprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func endpointsByNICinitLockNames() {} + +func init() { + endpointsByNICinitLockNames() + endpointsByNICprefixIndex = locking.NewMutexClass(reflect.TypeOf(endpointsByNICRWMutex{}), endpointsByNIClockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro.go new file mode 100644 index 000000000..c59c023dd --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro.go @@ -0,0 +1,530 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package stack + +import ( + "fmt" + "time" + + "gvisor.dev/gvisor/pkg/atomicbitops" + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/header" +) + +// TODO(b/256037250): I still see the occasional SACK block in the zero-loss +// benchmark, which should not happen. +// TODO(b/256037250): Some dispatchers, e.g. XDP and RecvMmsg, can receive +// multiple packets at a time. Even if the GRO interval is 0, there is an +// opportunity for coalescing. +// TODO(b/256037250): We're doing some header parsing here, which presents the +// opportunity to skip it later. +// TODO(b/256037250): Disarm or ignore the timer when GRO is empty. +// TODO(b/256037250): We may be able to remove locking by pairing +// groDispatchers with link endpoint dispatchers. + +const ( + // groNBuckets is the number of GRO buckets. + groNBuckets = 8 + + groNBucketsMask = groNBuckets - 1 + + // groBucketSize is the size of each GRO bucket. + groBucketSize = 8 + + // groMaxPacketSize is the maximum size of a GRO'd packet. + groMaxPacketSize = 1 << 16 // 65KB. +) + +// A groBucket holds packets that are undergoing GRO. +type groBucket struct { + // mu protects the fields of a bucket. + mu sync.Mutex + + // count is the number of packets in the bucket. + // +checklocks:mu + count int + + // packets is the linked list of packets. + // +checklocks:mu + packets groPacketList + + // packetsPrealloc and allocIdxs are used to preallocate and reuse + // groPacket structs and avoid allocation. + // +checklocks:mu + packetsPrealloc [groBucketSize]groPacket + + // +checklocks:mu + allocIdxs [groBucketSize]int +} + +// +checklocks:gb.mu +func (gb *groBucket) full() bool { + return gb.count == groBucketSize +} + +// insert inserts pkt into the bucket. +// +checklocks:gb.mu +func (gb *groBucket) insert(pkt PacketBufferPtr, ipHdr header.IPv4, tcpHdr header.TCP, ep NetworkEndpoint) { + groPkt := &gb.packetsPrealloc[gb.allocIdxs[gb.count]] + *groPkt = groPacket{ + pkt: pkt, + created: time.Now(), + ep: ep, + ipHdr: ipHdr, + tcpHdr: tcpHdr, + initialLength: ipHdr.TotalLength(), + idx: groPkt.idx, + } + gb.count++ + gb.packets.PushBack(groPkt) +} + +// removeOldest removes the oldest packet from gb and returns the contained +// PacketBufferPtr. gb must not be empty. +// +checklocks:gb.mu +func (gb *groBucket) removeOldest() PacketBufferPtr { + pkt := gb.packets.Front() + gb.packets.Remove(pkt) + gb.count-- + gb.allocIdxs[gb.count] = pkt.idx + ret := pkt.pkt + pkt.reset() + return ret +} + +// removeOne removes a packet from gb. It also resets pkt to its zero value. +// +checklocks:gb.mu +func (gb *groBucket) removeOne(pkt *groPacket) { + gb.packets.Remove(pkt) + gb.count-- + gb.allocIdxs[gb.count] = pkt.idx + pkt.reset() +} + +// findGROPacket returns the groPkt that matches ipHdr and tcpHdr, or nil if +// none exists. It also returns whether the groPkt should be flushed based on +// differences between the two headers. +// +checklocks:gb.mu +func (gb *groBucket) findGROPacket(ipHdr header.IPv4, tcpHdr header.TCP) (*groPacket, bool) { + for groPkt := gb.packets.Front(); groPkt != nil; groPkt = groPkt.Next() { + // Do the addresses match? + if ipHdr.SourceAddress() != groPkt.ipHdr.SourceAddress() || ipHdr.DestinationAddress() != groPkt.ipHdr.DestinationAddress() { + continue + } + + // Do the ports match? + if tcpHdr.SourcePort() != groPkt.tcpHdr.SourcePort() || tcpHdr.DestinationPort() != groPkt.tcpHdr.DestinationPort() { + continue + } + + // We've found a packet of the same flow. + + // IP checks. + TOS, _ := ipHdr.TOS() + groTOS, _ := groPkt.ipHdr.TOS() + if ipHdr.TTL() != groPkt.ipHdr.TTL() || TOS != groTOS { + return groPkt, true + } + + // TCP checks. + flags := tcpHdr.Flags() + groPktFlags := groPkt.tcpHdr.Flags() + dataOff := tcpHdr.DataOffset() + if flags&header.TCPFlagCwr != 0 || // Is congestion control occurring? + (flags^groPktFlags)&^(header.TCPFlagCwr|header.TCPFlagFin|header.TCPFlagPsh) != 0 || // Do the flags differ besides CRW, FIN, and PSH? + tcpHdr.AckNumber() != groPkt.tcpHdr.AckNumber() || // Do the ACKs match? + dataOff != groPkt.tcpHdr.DataOffset() || // Are the TCP headers the same length? + groPkt.tcpHdr.SequenceNumber()+uint32(groPkt.payloadSize()) != tcpHdr.SequenceNumber() { // Does the incoming packet match the expected sequence number? + return groPkt, true + } + // The options, including timestamps, must be identical. + for i := header.TCPMinimumSize; i < int(dataOff); i++ { + if tcpHdr[i] != groPkt.tcpHdr[i] { + return groPkt, true + } + } + + // There's an upper limit on coalesced packet size. + if int(ipHdr.TotalLength())-header.IPv4MinimumSize-int(dataOff)+groPkt.pkt.Data().Size() >= groMaxPacketSize { + return groPkt, true + } + + return groPkt, false + } + + return nil, false +} + +// A groPacket is packet undergoing GRO. It may be several packets coalesced +// together. +type groPacket struct { + // groPacketEntry is an intrusive list. + groPacketEntry + + // pkt is the coalesced packet. + pkt PacketBufferPtr + + // ipHdr is the IP header for the coalesced packet. + ipHdr header.IPv4 + + // tcpHdr is the TCP header for the coalesced packet. + tcpHdr header.TCP + + // created is when the packet was received. + created time.Time + + // ep is the endpoint to which the packet will be sent after GRO. + ep NetworkEndpoint + + // initialLength is the length of the first packet in the flow. It is + // used as a best-effort guess at MSS: senders will send MSS-sized + // packets until they run out of data, so we coalesce as long as + // packets are the same size. + initialLength uint16 + + // idx is the groPacket's index in its bucket packetsPrealloc. It is + // immutable. + idx int +} + +// reset resets all mutable fields of the groPacket. +func (pk *groPacket) reset() { + *pk = groPacket{ + idx: pk.idx, + } +} + +// payloadSize is the payload size of the coalesced packet, which does not +// include the network or transport headers. +func (pk *groPacket) payloadSize() uint16 { + return pk.ipHdr.TotalLength() - header.IPv4MinimumSize - uint16(pk.tcpHdr.DataOffset()) +} + +// groDispatcher coalesces incoming packets to increase throughput. +type groDispatcher struct { + // newInterval notifies about changes to the interval. + newInterval chan struct{} + // intervalNS is the interval in nanoseconds. + intervalNS atomicbitops.Int64 + // stop instructs the GRO dispatcher goroutine to stop. + stop chan struct{} + + buckets [groNBuckets]groBucket + wg sync.WaitGroup +} + +func (gd *groDispatcher) init(interval time.Duration) { + gd.intervalNS.Store(interval.Nanoseconds()) + gd.newInterval = make(chan struct{}, 1) + gd.stop = make(chan struct{}) + + for i := range gd.buckets { + bucket := &gd.buckets[i] + bucket.mu.Lock() + for j := range bucket.packetsPrealloc { + bucket.allocIdxs[j] = j + bucket.packetsPrealloc[j].idx = j + } + bucket.mu.Unlock() + } + + gd.start(interval) +} + +// start spawns a goroutine that flushes the GRO periodically based on the +// interval. +func (gd *groDispatcher) start(interval time.Duration) { + gd.wg.Add(1) + + go func(interval time.Duration) { + defer gd.wg.Done() + + var ch <-chan time.Time + if interval == 0 { + // Never run. + ch = make(<-chan time.Time) + } else { + ticker := time.NewTicker(interval) + ch = ticker.C + } + for { + select { + case <-gd.newInterval: + interval = time.Duration(gd.intervalNS.Load()) * time.Nanosecond + if interval == 0 { + // Never run. Flush any existing GRO packets. + gd.flushAll() + ch = make(<-chan time.Time) + } else { + ticker := time.NewTicker(interval) + ch = ticker.C + } + case <-ch: + gd.flush() + case <-gd.stop: + return + } + } + }(interval) +} + +func (gd *groDispatcher) getInterval() time.Duration { + return time.Duration(gd.intervalNS.Load()) * time.Nanosecond +} + +func (gd *groDispatcher) setInterval(interval time.Duration) { + gd.intervalNS.Store(interval.Nanoseconds()) + gd.newInterval <- struct{}{} +} + +// dispatch sends pkt up the stack after it undergoes GRO coalescing. +func (gd *groDispatcher) dispatch(pkt PacketBufferPtr, netProto tcpip.NetworkProtocolNumber, ep NetworkEndpoint) { + // If GRO is disabled simply pass the packet along. + if gd.intervalNS.Load() == 0 { + ep.HandlePacket(pkt) + return + } + + // Immediately get the IPv4 and TCP headers. We need a way to hash the + // packet into its bucket, which requires addresses and ports. Linux + // simply gets a hash passed by hardware, but we're not so lucky. + + // We only GRO IPv4 packets. + if netProto != header.IPv4ProtocolNumber { + ep.HandlePacket(pkt) + return + } + + // We only GRO TCP4 packets. The check for the transport protocol + // number is done below so that we can PullUp both the IP and TCP + // headers together. + hdrBytes, ok := pkt.Data().PullUp(header.IPv4MinimumSize + header.TCPMinimumSize) + if !ok { + ep.HandlePacket(pkt) + return + } + ipHdr := header.IPv4(hdrBytes) + + // We only handle atomic packets. That's the vast majority of traffic, + // and simplifies handling. + if ipHdr.FragmentOffset() != 0 || ipHdr.Flags()&header.IPv4FlagMoreFragments != 0 || ipHdr.Flags()&header.IPv4FlagDontFragment == 0 { + ep.HandlePacket(pkt) + return + } + + // We only handle TCP packets without IP options. + if ipHdr.HeaderLength() != header.IPv4MinimumSize || tcpip.TransportProtocolNumber(ipHdr.Protocol()) != header.TCPProtocolNumber { + ep.HandlePacket(pkt) + return + } + tcpHdr := header.TCP(hdrBytes[header.IPv4MinimumSize:]) + dataOff := tcpHdr.DataOffset() + if dataOff < header.TCPMinimumSize { + // Malformed packet: will be handled further up the stack. + ep.HandlePacket(pkt) + return + } + hdrBytes, ok = pkt.Data().PullUp(header.IPv4MinimumSize + int(dataOff)) + if !ok { + // Malformed packet: will be handled further up the stack. + ep.HandlePacket(pkt) + return + } + + tcpHdr = header.TCP(hdrBytes[header.IPv4MinimumSize:]) + + // If either checksum is bad, flush the packet. Since we don't know + // what bits were flipped, we can't identify this packet with a flow. + tcpPayloadSize := ipHdr.TotalLength() - header.IPv4MinimumSize - uint16(dataOff) + if !pkt.RXChecksumValidated { + if !ipHdr.IsValid(pkt.Data().Size()) || !ipHdr.IsChecksumValid() { + ep.HandlePacket(pkt) + return + } + payloadChecksum := pkt.Data().ChecksumAtOffset(header.IPv4MinimumSize + int(dataOff)) + if !tcpHdr.IsChecksumValid(ipHdr.SourceAddress(), ipHdr.DestinationAddress(), payloadChecksum, tcpPayloadSize) { + ep.HandlePacket(pkt) + return + } + // We've validated the checksum, no reason for others to do it + // again. + pkt.RXChecksumValidated = true + } + + // Now we can get the bucket for the packet. + bucket := &gd.buckets[gd.bucketForPacket(ipHdr, tcpHdr)&groNBucketsMask] + bucket.mu.Lock() + groPkt, flushGROPkt := bucket.findGROPacket(ipHdr, tcpHdr) + + // Flush groPkt or merge the packets. + flags := tcpHdr.Flags() + if flushGROPkt { + // Flush the existing GRO packet. Don't hold bucket.mu while + // processing the packet. + pkt := groPkt.pkt + bucket.removeOne(groPkt) + bucket.mu.Unlock() + ep.HandlePacket(pkt) + pkt.DecRef() + bucket.mu.Lock() + groPkt = nil + } else if groPkt != nil { + // Merge pkt in to GRO packet. + buf := pkt.Data().ToBuffer() + buf.TrimFront(header.IPv4MinimumSize + int64(dataOff)) + groPkt.pkt.Data().MergeBuffer(&buf) + buf.Release() + // Add flags from the packet to the GRO packet. + groPkt.tcpHdr.SetFlags(uint8(groPkt.tcpHdr.Flags() | (flags & (header.TCPFlagFin | header.TCPFlagPsh)))) + // Update the IP total length. + groPkt.ipHdr.SetTotalLength(groPkt.ipHdr.TotalLength() + uint16(tcpPayloadSize)) + + pkt = PacketBufferPtr{} + } + + // Flush if the packet isn't the same size as the previous packets or + // if certain flags are set. The reason for checking size equality is: + // - If the packet is smaller than the others, this is likely the end + // of some message. Peers will send MSS-sized packets until they have + // insufficient data to do so. + // - If the packet is larger than the others, this packet is either + // malformed, a local GSO packet, or has already been handled by host + // GRO. + flush := header.TCPFlags(flags)&(header.TCPFlagUrg|header.TCPFlagPsh|header.TCPFlagRst|header.TCPFlagSyn|header.TCPFlagFin) != 0 + if groPkt != nil { + flush = flush || ipHdr.TotalLength() != groPkt.initialLength + } + + switch { + case flush && groPkt != nil: + // A merge occurred and we need to flush groPkt. + pkt := groPkt.pkt + bucket.removeOne(groPkt) + bucket.mu.Unlock() + ep.HandlePacket(pkt) + pkt.DecRef() + case flush && groPkt == nil: + // No merge occurred and the incoming packet needs to be flushed. + bucket.mu.Unlock() + ep.HandlePacket(pkt) + case !flush && groPkt == nil: + // New flow and we don't need to flush. Insert pkt into GRO. + if bucket.full() { + // Head is always the oldest packet + toFlush := bucket.removeOldest() + bucket.insert(pkt.IncRef(), ipHdr, tcpHdr, ep) + bucket.mu.Unlock() + ep.HandlePacket(toFlush) + toFlush.DecRef() + } else { + bucket.insert(pkt.IncRef(), ipHdr, tcpHdr, ep) + bucket.mu.Unlock() + } + default: + // A merge occurred and we don't need to flush anything. + bucket.mu.Unlock() + } +} + +func (gd *groDispatcher) bucketForPacket(ipHdr header.IPv4, tcpHdr header.TCP) int { + // TODO(b/256037250): Use jenkins or checksum. Write a test to print + // distribution. + var sum int + for _, val := range []byte(ipHdr.SourceAddress()) { + sum += int(val) + } + for _, val := range []byte(ipHdr.DestinationAddress()) { + sum += int(val) + } + sum += int(tcpHdr.SourcePort()) + sum += int(tcpHdr.DestinationPort()) + return sum +} + +// flush sends any packets older than interval up the stack. +func (gd *groDispatcher) flush() { + interval := gd.intervalNS.Load() + old := time.Now().Add(-time.Duration(interval) * time.Nanosecond) + gd.flushSince(old) +} + +func (gd *groDispatcher) flushSince(old time.Time) { + type pair struct { + pkt PacketBufferPtr + ep NetworkEndpoint + } + + for i := range gd.buckets { + // Put packets in a slice so we don't have to hold bucket.mu + // when we call HandlePacket. + var pairsBacking [groNBuckets]pair + pairs := pairsBacking[:0] + + bucket := &gd.buckets[i] + bucket.mu.Lock() + for groPkt := bucket.packets.Front(); groPkt != nil; groPkt = groPkt.Next() { + if groPkt.created.Before(old) { + pairs = append(pairs, pair{groPkt.pkt, groPkt.ep}) + bucket.removeOne(groPkt) + } else { + // Packets are ordered by age, so we can move + // on once we find one that's too new. + break + } + } + bucket.mu.Unlock() + + for _, pair := range pairs { + pair.ep.HandlePacket(pair.pkt) + pair.pkt.DecRef() + } + } +} + +func (gd *groDispatcher) flushAll() { + gd.flushSince(time.Now()) +} + +// close stops the GRO goroutine and releases any held packets. +func (gd *groDispatcher) close() { + gd.stop <- struct{}{} + gd.wg.Wait() + + for i := range gd.buckets { + bucket := &gd.buckets[i] + bucket.mu.Lock() + for groPkt := bucket.packets.Front(); groPkt != nil; groPkt = groPkt.Next() { + groPkt.pkt.DecRef() + } + bucket.mu.Unlock() + } +} + +// String implements fmt.Stringer. +func (gd *groDispatcher) String() string { + ret := "GRO state: \n" + for i := range gd.buckets { + bucket := &gd.buckets[i] + bucket.mu.Lock() + ret += fmt.Sprintf("bucket %d: %d packets: ", i, bucket.count) + for groPkt := bucket.packets.Front(); groPkt != nil; groPkt = groPkt.Next() { + ret += fmt.Sprintf("%s (%d), ", groPkt.created, groPkt.pkt.Data().Size()) + } + ret += "\n" + bucket.mu.Unlock() + } + return ret +} diff --git a/vendor/gvisor.dev/gvisor/pkg/refs/weak_ref_list.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro_packet_list.go similarity index 61% rename from vendor/gvisor.dev/gvisor/pkg/refs/weak_ref_list.go rename to vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro_packet_list.go index 793c25387..86d2f49fe 100644 --- a/vendor/gvisor.dev/gvisor/pkg/refs/weak_ref_list.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/gro_packet_list.go @@ -1,4 +1,4 @@ -package refs +package stack // ElementMapper provides an identity mapping by default. // @@ -6,14 +6,14 @@ package refs // objects, if they are not the same. An ElementMapper is not typically // required if: Linker is left as is, Element is left as is, or Linker and // Element are the same type. -type weakRefElementMapper struct{} +type groPacketElementMapper struct{} // linkerFor maps an Element to a Linker. // // This default implementation should be inlined. // //go:nosplit -func (weakRefElementMapper) linkerFor(elem *WeakRef) *WeakRef { return elem } +func (groPacketElementMapper) linkerFor(elem *groPacket) *groPacket { return elem } // List is an intrusive list. Entries can be added to or removed from the list // in O(1) time and with no additional memory allocations. @@ -27,13 +27,13 @@ func (weakRefElementMapper) linkerFor(elem *WeakRef) *WeakRef { return elem } // } // // +stateify savable -type weakRefList struct { - head *WeakRef - tail *WeakRef +type groPacketList struct { + head *groPacket + tail *groPacket } // Reset resets list l to the empty state. -func (l *weakRefList) Reset() { +func (l *groPacketList) Reset() { l.head = nil l.tail = nil } @@ -41,21 +41,21 @@ func (l *weakRefList) Reset() { // Empty returns true iff the list is empty. // //go:nosplit -func (l *weakRefList) Empty() bool { +func (l *groPacketList) Empty() bool { return l.head == nil } // Front returns the first element of list l or nil. // //go:nosplit -func (l *weakRefList) Front() *WeakRef { +func (l *groPacketList) Front() *groPacket { return l.head } // Back returns the last element of list l or nil. // //go:nosplit -func (l *weakRefList) Back() *WeakRef { +func (l *groPacketList) Back() *groPacket { return l.tail } @@ -64,8 +64,8 @@ func (l *weakRefList) Back() *WeakRef { // NOTE: This is an O(n) operation. // //go:nosplit -func (l *weakRefList) Len() (count int) { - for e := l.Front(); e != nil; e = (weakRefElementMapper{}.linkerFor(e)).Next() { +func (l *groPacketList) Len() (count int) { + for e := l.Front(); e != nil; e = (groPacketElementMapper{}.linkerFor(e)).Next() { count++ } return count @@ -74,12 +74,12 @@ func (l *weakRefList) Len() (count int) { // PushFront inserts the element e at the front of list l. // //go:nosplit -func (l *weakRefList) PushFront(e *WeakRef) { - linker := weakRefElementMapper{}.linkerFor(e) +func (l *groPacketList) PushFront(e *groPacket) { + linker := groPacketElementMapper{}.linkerFor(e) linker.SetNext(l.head) linker.SetPrev(nil) if l.head != nil { - weakRefElementMapper{}.linkerFor(l.head).SetPrev(e) + groPacketElementMapper{}.linkerFor(l.head).SetPrev(e) } else { l.tail = e } @@ -90,13 +90,13 @@ func (l *weakRefList) PushFront(e *WeakRef) { // PushFrontList inserts list m at the start of list l, emptying m. // //go:nosplit -func (l *weakRefList) PushFrontList(m *weakRefList) { +func (l *groPacketList) PushFrontList(m *groPacketList) { if l.head == nil { l.head = m.head l.tail = m.tail } else if m.head != nil { - weakRefElementMapper{}.linkerFor(l.head).SetPrev(m.tail) - weakRefElementMapper{}.linkerFor(m.tail).SetNext(l.head) + groPacketElementMapper{}.linkerFor(l.head).SetPrev(m.tail) + groPacketElementMapper{}.linkerFor(m.tail).SetNext(l.head) l.head = m.head } @@ -107,12 +107,12 @@ func (l *weakRefList) PushFrontList(m *weakRefList) { // PushBack inserts the element e at the back of list l. // //go:nosplit -func (l *weakRefList) PushBack(e *WeakRef) { - linker := weakRefElementMapper{}.linkerFor(e) +func (l *groPacketList) PushBack(e *groPacket) { + linker := groPacketElementMapper{}.linkerFor(e) linker.SetNext(nil) linker.SetPrev(l.tail) if l.tail != nil { - weakRefElementMapper{}.linkerFor(l.tail).SetNext(e) + groPacketElementMapper{}.linkerFor(l.tail).SetNext(e) } else { l.head = e } @@ -123,13 +123,13 @@ func (l *weakRefList) PushBack(e *WeakRef) { // PushBackList inserts list m at the end of list l, emptying m. // //go:nosplit -func (l *weakRefList) PushBackList(m *weakRefList) { +func (l *groPacketList) PushBackList(m *groPacketList) { if l.head == nil { l.head = m.head l.tail = m.tail } else if m.head != nil { - weakRefElementMapper{}.linkerFor(l.tail).SetNext(m.head) - weakRefElementMapper{}.linkerFor(m.head).SetPrev(l.tail) + groPacketElementMapper{}.linkerFor(l.tail).SetNext(m.head) + groPacketElementMapper{}.linkerFor(m.head).SetPrev(l.tail) l.tail = m.tail } @@ -140,9 +140,9 @@ func (l *weakRefList) PushBackList(m *weakRefList) { // InsertAfter inserts e after b. // //go:nosplit -func (l *weakRefList) InsertAfter(b, e *WeakRef) { - bLinker := weakRefElementMapper{}.linkerFor(b) - eLinker := weakRefElementMapper{}.linkerFor(e) +func (l *groPacketList) InsertAfter(b, e *groPacket) { + bLinker := groPacketElementMapper{}.linkerFor(b) + eLinker := groPacketElementMapper{}.linkerFor(e) a := bLinker.Next() @@ -151,7 +151,7 @@ func (l *weakRefList) InsertAfter(b, e *WeakRef) { bLinker.SetNext(e) if a != nil { - weakRefElementMapper{}.linkerFor(a).SetPrev(e) + groPacketElementMapper{}.linkerFor(a).SetPrev(e) } else { l.tail = e } @@ -160,9 +160,9 @@ func (l *weakRefList) InsertAfter(b, e *WeakRef) { // InsertBefore inserts e before a. // //go:nosplit -func (l *weakRefList) InsertBefore(a, e *WeakRef) { - aLinker := weakRefElementMapper{}.linkerFor(a) - eLinker := weakRefElementMapper{}.linkerFor(e) +func (l *groPacketList) InsertBefore(a, e *groPacket) { + aLinker := groPacketElementMapper{}.linkerFor(a) + eLinker := groPacketElementMapper{}.linkerFor(e) b := aLinker.Prev() eLinker.SetNext(a) @@ -170,7 +170,7 @@ func (l *weakRefList) InsertBefore(a, e *WeakRef) { aLinker.SetPrev(e) if b != nil { - weakRefElementMapper{}.linkerFor(b).SetNext(e) + groPacketElementMapper{}.linkerFor(b).SetNext(e) } else { l.head = e } @@ -179,19 +179,19 @@ func (l *weakRefList) InsertBefore(a, e *WeakRef) { // Remove removes e from l. // //go:nosplit -func (l *weakRefList) Remove(e *WeakRef) { - linker := weakRefElementMapper{}.linkerFor(e) +func (l *groPacketList) Remove(e *groPacket) { + linker := groPacketElementMapper{}.linkerFor(e) prev := linker.Prev() next := linker.Next() if prev != nil { - weakRefElementMapper{}.linkerFor(prev).SetNext(next) + groPacketElementMapper{}.linkerFor(prev).SetNext(next) } else if l.head == e { l.head = next } if next != nil { - weakRefElementMapper{}.linkerFor(next).SetPrev(prev) + groPacketElementMapper{}.linkerFor(next).SetPrev(prev) } else if l.tail == e { l.tail = prev } @@ -205,35 +205,35 @@ func (l *weakRefList) Remove(e *WeakRef) { // methods needed by List. // // +stateify savable -type weakRefEntry struct { - next *WeakRef - prev *WeakRef +type groPacketEntry struct { + next *groPacket + prev *groPacket } // Next returns the entry that follows e in the list. // //go:nosplit -func (e *weakRefEntry) Next() *WeakRef { +func (e *groPacketEntry) Next() *groPacket { return e.next } // Prev returns the entry that precedes e in the list. // //go:nosplit -func (e *weakRefEntry) Prev() *WeakRef { +func (e *groPacketEntry) Prev() *groPacket { return e.prev } // SetNext assigns 'entry' as the entry that follows e in the list. // //go:nosplit -func (e *weakRefEntry) SetNext(elem *WeakRef) { +func (e *groPacketEntry) SetNext(elem *groPacket) { e.next = elem } // SetPrev assigns 'entry' as the entry that precedes e in the list. // //go:nosplit -func (e *weakRefEntry) SetPrev(elem *WeakRef) { +func (e *groPacketEntry) SetPrev(elem *groPacket) { e.prev = elem } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go index eb50f1347..0ad5303c8 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go @@ -281,7 +281,7 @@ type checkTable struct { // - Calls to dynamic functions, which can allocate. // // +checkescape:hard -func (it *IPTables) shouldSkipOrPopulateTables(tables []checkTable, pkt *PacketBuffer) bool { +func (it *IPTables) shouldSkipOrPopulateTables(tables []checkTable, pkt PacketBufferPtr) bool { switch pkt.NetworkProtocolNumber { case header.IPv4ProtocolNumber, header.IPv6ProtocolNumber: default: @@ -315,8 +315,8 @@ func (it *IPTables) shouldSkipOrPopulateTables(tables []checkTable, pkt *PacketB // This is called in the hot path even when iptables are disabled, so we ensure // that it does not allocate. Note that called functions (e.g. // getConnAndUpdate) can allocate. -// +checkescape -func (it *IPTables) CheckPrerouting(pkt *PacketBuffer, addressEP AddressableEndpoint, inNicName string) bool { +// TODO(b/233951539): checkescape fails on arm sometimes. Fix and re-add. +func (it *IPTables) CheckPrerouting(pkt PacketBufferPtr, addressEP AddressableEndpoint, inNicName string) bool { tables := [...]checkTable{ { fn: check, @@ -353,8 +353,8 @@ func (it *IPTables) CheckPrerouting(pkt *PacketBuffer, addressEP AddressableEndp // This is called in the hot path even when iptables are disabled, so we ensure // that it does not allocate. Note that called functions (e.g. // getConnAndUpdate) can allocate. -// +checkescape -func (it *IPTables) CheckInput(pkt *PacketBuffer, inNicName string) bool { +// TODO(b/233951539): checkescape fails on arm sometimes. Fix and re-add. +func (it *IPTables) CheckInput(pkt PacketBufferPtr, inNicName string) bool { tables := [...]checkTable{ { fn: checkNAT, @@ -393,8 +393,8 @@ func (it *IPTables) CheckInput(pkt *PacketBuffer, inNicName string) bool { // This is called in the hot path even when iptables are disabled, so we ensure // that it does not allocate. Note that called functions (e.g. // getConnAndUpdate) can allocate. -// +checkescape -func (it *IPTables) CheckForward(pkt *PacketBuffer, inNicName, outNicName string) bool { +// TODO(b/233951539): checkescape fails on arm sometimes. Fix and re-add. +func (it *IPTables) CheckForward(pkt PacketBufferPtr, inNicName, outNicName string) bool { tables := [...]checkTable{ { fn: check, @@ -425,8 +425,8 @@ func (it *IPTables) CheckForward(pkt *PacketBuffer, inNicName, outNicName string // This is called in the hot path even when iptables are disabled, so we ensure // that it does not allocate. Note that called functions (e.g. // getConnAndUpdate) can allocate. -// +checkescape -func (it *IPTables) CheckOutput(pkt *PacketBuffer, r *Route, outNicName string) bool { +// TODO(b/233951539): checkescape fails on arm sometimes. Fix and re-add. +func (it *IPTables) CheckOutput(pkt PacketBufferPtr, r *Route, outNicName string) bool { tables := [...]checkTable{ { fn: check, @@ -469,8 +469,8 @@ func (it *IPTables) CheckOutput(pkt *PacketBuffer, r *Route, outNicName string) // This is called in the hot path even when iptables are disabled, so we ensure // that it does not allocate. Note that called functions (e.g. // getConnAndUpdate) can allocate. -// +checkescape -func (it *IPTables) CheckPostrouting(pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, outNicName string) bool { +// TODO(b/233951539): checkescape fails on arm sometimes. Fix and re-add. +func (it *IPTables) CheckPostrouting(pkt PacketBufferPtr, r *Route, addressEP AddressableEndpoint, outNicName string) bool { tables := [...]checkTable{ { fn: check, @@ -501,16 +501,16 @@ func (it *IPTables) CheckPostrouting(pkt *PacketBuffer, r *Route, addressEP Addr // Note: this used to omit the *IPTables parameter, but doing so caused // unnecessary allocations. -type checkTableFn func(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool +type checkTableFn func(it *IPTables, table Table, hook Hook, pkt PacketBufferPtr, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool -func checkNAT(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { +func checkNAT(it *IPTables, table Table, hook Hook, pkt PacketBufferPtr, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { return it.checkNAT(table, hook, pkt, r, addressEP, inNicName, outNicName) } // checkNAT runs the packet through the NAT table. // // See check. -func (it *IPTables) checkNAT(table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { +func (it *IPTables) checkNAT(table Table, hook Hook, pkt PacketBufferPtr, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { t := pkt.tuple if t != nil && t.conn.handlePacket(pkt, hook, r) { return true @@ -548,7 +548,7 @@ func (it *IPTables) checkNAT(table Table, hook Hook, pkt *PacketBuffer, r *Route return true } -func check(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { +func check(it *IPTables, table Table, hook Hook, pkt PacketBufferPtr, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { return it.check(table, hook, pkt, r, addressEP, inNicName, outNicName) } @@ -557,7 +557,7 @@ func check(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, ad // network stack or tables, or false when it must be dropped. // // Precondition: The packet's network and transport header must be set. -func (it *IPTables) check(table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { +func (it *IPTables) check(table Table, hook Hook, pkt PacketBufferPtr, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool { ruleIdx := table.BuiltinChains[hook] switch verdict := it.checkChain(hook, pkt, table, ruleIdx, r, addressEP, inNicName, outNicName); verdict { // If the table returns Accept, move on to the next table. @@ -610,7 +610,7 @@ func (it *IPTables) startReaper(interval time.Duration) { // Preconditions: // - pkt is a IPv4 packet of at least length header.IPv4MinimumSize. // - pkt.NetworkHeader is not nil. -func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) chainVerdict { +func (it *IPTables) checkChain(hook Hook, pkt PacketBufferPtr, table Table, ruleIdx int, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) chainVerdict { // Start from ruleIdx and walk the list of rules until a rule gives us // a verdict. for ruleIdx < len(table.Rules) { @@ -657,7 +657,10 @@ func (it *IPTables) checkChain(hook Hook, pkt *PacketBuffer, table Table, ruleId // Preconditions: // - pkt is a IPv4 packet of at least length header.IPv4MinimumSize. // - pkt.NetworkHeader is not nil. -func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx int, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) (RuleVerdict, int) { +// +// * pkt is a IPv4 packet of at least length header.IPv4MinimumSize. +// * pkt.NetworkHeader is not nil. +func (it *IPTables) checkRule(hook Hook, pkt PacketBufferPtr, table Table, ruleIdx int, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) (RuleVerdict, int) { rule := table.Rules[ruleIdx] // Check whether the packet matches the IP header filter. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_mutex.go new file mode 100644 index 000000000..984498d14 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type ipTablesRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var ipTableslockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type ipTableslockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *ipTablesRWMutex) Lock() { + locking.AddGLock(ipTablesprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *ipTablesRWMutex) NestedLock(i ipTableslockNameIndex) { + locking.AddGLock(ipTablesprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *ipTablesRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(ipTablesprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *ipTablesRWMutex) NestedUnlock(i ipTableslockNameIndex) { + m.mu.Unlock() + locking.DelGLock(ipTablesprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *ipTablesRWMutex) RLock() { + locking.AddGLock(ipTablesprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *ipTablesRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(ipTablesprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *ipTablesRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *ipTablesRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *ipTablesRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var ipTablesprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func ipTablesinitLockNames() {} + +func init() { + ipTablesinitLockNames() + ipTablesprefixIndex = locking.NewMutexClass(reflect.TypeOf(ipTablesRWMutex{}), ipTableslockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_targets.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_targets.go index d93670d6b..5b4a736fe 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_targets.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_targets.go @@ -30,7 +30,7 @@ type AcceptTarget struct { } // Action implements Target.Action. -func (*AcceptTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { +func (*AcceptTarget) Action(PacketBufferPtr, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { return RuleAccept, 0 } @@ -41,14 +41,14 @@ type DropTarget struct { } // Action implements Target.Action. -func (*DropTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { +func (*DropTarget) Action(PacketBufferPtr, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { return RuleDrop, 0 } // RejectIPv4WithHandler handles rejecting a packet. type RejectIPv4WithHandler interface { // SendRejectionError sends an error packet in response to the packet. - SendRejectionError(pkt *PacketBuffer, rejectWith RejectIPv4WithICMPType, inputHook bool) tcpip.Error + SendRejectionError(pkt PacketBufferPtr, rejectWith RejectIPv4WithICMPType, inputHook bool) tcpip.Error } // RejectIPv4WithICMPType indicates the type of ICMP error that should be sent. @@ -73,7 +73,7 @@ type RejectIPv4Target struct { } // Action implements Target.Action. -func (rt *RejectIPv4Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) { +func (rt *RejectIPv4Target) Action(pkt PacketBufferPtr, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) { switch hook { case Input, Forward, Output: // There is nothing reasonable for us to do in response to an error here; @@ -90,7 +90,7 @@ func (rt *RejectIPv4Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ Add // RejectIPv6WithHandler handles rejecting a packet. type RejectIPv6WithHandler interface { // SendRejectionError sends an error packet in response to the packet. - SendRejectionError(pkt *PacketBuffer, rejectWith RejectIPv6WithICMPType, forwardingHook bool) tcpip.Error + SendRejectionError(pkt PacketBufferPtr, rejectWith RejectIPv6WithICMPType, forwardingHook bool) tcpip.Error } // RejectIPv6WithICMPType indicates the type of ICMP error that should be sent. @@ -113,7 +113,7 @@ type RejectIPv6Target struct { } // Action implements Target.Action. -func (rt *RejectIPv6Target) Action(pkt *PacketBuffer, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) { +func (rt *RejectIPv6Target) Action(pkt PacketBufferPtr, hook Hook, _ *Route, _ AddressableEndpoint) (RuleVerdict, int) { switch hook { case Input, Forward, Output: // There is nothing reasonable for us to do in response to an error here; @@ -135,7 +135,7 @@ type ErrorTarget struct { } // Action implements Target.Action. -func (*ErrorTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { +func (*ErrorTarget) Action(PacketBufferPtr, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { log.Debugf("ErrorTarget triggered.") return RuleDrop, 0 } @@ -150,7 +150,7 @@ type UserChainTarget struct { } // Action implements Target.Action. -func (*UserChainTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { +func (*UserChainTarget) Action(PacketBufferPtr, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { panic("UserChainTarget should never be called.") } @@ -162,7 +162,7 @@ type ReturnTarget struct { } // Action implements Target.Action. -func (*ReturnTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { +func (*ReturnTarget) Action(PacketBufferPtr, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) { return RuleReturn, 0 } @@ -185,7 +185,7 @@ type DNATTarget struct { } // Action implements Target.Action. -func (rt *DNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { +func (rt *DNATTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { // Sanity check. if rt.NetworkProtocol != pkt.NetworkProtocolNumber { panic(fmt.Sprintf( @@ -219,7 +219,7 @@ type RedirectTarget struct { } // Action implements Target.Action. -func (rt *RedirectTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { +func (rt *RedirectTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { // Sanity check. if rt.NetworkProtocol != pkt.NetworkProtocolNumber { panic(fmt.Sprintf( @@ -257,7 +257,7 @@ type SNATTarget struct { NetworkProtocol tcpip.NetworkProtocolNumber } -func dnatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) { +func dnatAction(pkt PacketBufferPtr, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) { return natAction(pkt, hook, r, portOrIdentRange{start: port, size: 1}, address, true /* dnat */) } @@ -278,7 +278,7 @@ func targetPortRangeForTCPAndUDP(originalSrcPort uint16) portOrIdentRange { } } -func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) { +func snatAction(pkt PacketBufferPtr, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) { portsOrIdents := portOrIdentRange{start: port, size: 1} switch pkt.TransportProtocolNumber { @@ -301,7 +301,7 @@ func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcp return natAction(pkt, hook, r, portsOrIdents, address, false /* dnat */) } -func natAction(pkt *PacketBuffer, hook Hook, r *Route, portsOrIdents portOrIdentRange, address tcpip.Address, dnat bool) (RuleVerdict, int) { +func natAction(pkt PacketBufferPtr, hook Hook, r *Route, portsOrIdents portOrIdentRange, address tcpip.Address, dnat bool) (RuleVerdict, int) { // Drop the packet if network and transport header are not set. if len(pkt.NetworkHeader().Slice()) == 0 || len(pkt.TransportHeader().Slice()) == 0 { return RuleDrop, 0 @@ -316,7 +316,7 @@ func natAction(pkt *PacketBuffer, hook Hook, r *Route, portsOrIdents portOrIdent } // Action implements Target.Action. -func (st *SNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) { +func (st *SNATTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) { // Sanity check. if st.NetworkProtocol != pkt.NetworkProtocolNumber { panic(fmt.Sprintf( @@ -343,7 +343,7 @@ type MasqueradeTarget struct { } // Action implements Target.Action. -func (mt *MasqueradeTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { +func (mt *MasqueradeTarget) Action(pkt PacketBufferPtr, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) { // Sanity check. if mt.NetworkProtocol != pkt.NetworkProtocolNumber { panic(fmt.Sprintf( diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go index 12def5ccb..ff1c4270a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go @@ -18,7 +18,6 @@ import ( "fmt" "strings" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -85,7 +84,7 @@ type IPTables struct { reaper tcpip.Timer - mu sync.RWMutex + mu ipTablesRWMutex // v4Tables and v6tables map tableIDs to tables. They hold builtin // tables only, not user tables. // @@ -240,7 +239,7 @@ type IPHeaderFilter struct { // // Preconditions: pkt.NetworkHeader is set and is at least of the minimal IPv4 // or IPv6 header length. -func (fl IPHeaderFilter) match(pkt *PacketBuffer, hook Hook, inNicName, outNicName string) bool { +func (fl IPHeaderFilter) match(pkt PacketBufferPtr, hook Hook, inNicName, outNicName string) bool { // Extract header fields. var ( transProto tcpip.TransportProtocolNumber @@ -345,7 +344,7 @@ type Matcher interface { // used for suspicious packets. // // Precondition: packet.NetworkHeader is set. - Match(hook Hook, packet *PacketBuffer, inputInterfaceName, outputInterfaceName string) (matches bool, hotdrop bool) + Match(hook Hook, packet PacketBufferPtr, inputInterfaceName, outputInterfaceName string) (matches bool, hotdrop bool) } // A Target is the interface for taking an action for a packet. @@ -353,5 +352,5 @@ type Target interface { // Action takes an action on the packet and returns a verdict on how // traversal should (or should not) continue. If the return value is // Jump, it also returns the index of the rule to jump to. - Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) + Action(PacketBufferPtr, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/multi_port_endpoint_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/multi_port_endpoint_mutex.go new file mode 100644 index 000000000..7e2d58182 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/multi_port_endpoint_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type multiPortEndpointRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var multiPortEndpointlockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type multiPortEndpointlockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *multiPortEndpointRWMutex) Lock() { + locking.AddGLock(multiPortEndpointprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *multiPortEndpointRWMutex) NestedLock(i multiPortEndpointlockNameIndex) { + locking.AddGLock(multiPortEndpointprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *multiPortEndpointRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(multiPortEndpointprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *multiPortEndpointRWMutex) NestedUnlock(i multiPortEndpointlockNameIndex) { + m.mu.Unlock() + locking.DelGLock(multiPortEndpointprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *multiPortEndpointRWMutex) RLock() { + locking.AddGLock(multiPortEndpointprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *multiPortEndpointRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(multiPortEndpointprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *multiPortEndpointRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *multiPortEndpointRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *multiPortEndpointRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var multiPortEndpointprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func multiPortEndpointinitLockNames() {} + +func init() { + multiPortEndpointinitLockNames() + multiPortEndpointprefixIndex = locking.NewMutexClass(reflect.TypeOf(multiPortEndpointRWMutex{}), multiPortEndpointlockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache.go index 08857e1a9..c63740074 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache.go @@ -17,7 +17,6 @@ package stack import ( "fmt" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" ) @@ -48,7 +47,7 @@ type neighborCache struct { linkRes LinkAddressResolver mu struct { - sync.RWMutex + neighborCacheRWMutex cache map[tcpip.Address]*neighborEntry dynamic struct { @@ -122,9 +121,7 @@ func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address) *neighborEntr // If specified, the local address must be an address local to the interface the // neighbor cache belongs to. The local address is the source address of a // packet prompting NUD/link address resolution. -// -// TODO(gvisor.dev/issue/5151): Don't return the neighbor entry. -func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (NeighborEntry, <-chan struct{}, tcpip.Error) { +func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (*neighborEntry, <-chan struct{}, tcpip.Error) { entry := n.getOrCreateEntry(remoteAddr) entry.mu.Lock() defer entry.mu.Unlock() @@ -142,7 +139,7 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, onResolve fun if onResolve != nil { onResolve(LinkResolutionResult{LinkAddress: entry.mu.neigh.LinkAddr, Err: nil}) } - return entry.mu.neigh, nil, nil + return entry, nil, nil case Unknown, Incomplete, Unreachable: if onResolve != nil { entry.mu.onResolve = append(entry.mu.onResolve, onResolve) @@ -152,7 +149,7 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, onResolve fun entry.mu.done = make(chan struct{}) } entry.handlePacketQueuedLocked(localAddr) - return entry.mu.neigh, entry.mu.done, &tcpip.ErrWouldBlock{} + return entry, entry.mu.done, &tcpip.ErrWouldBlock{} default: panic(fmt.Sprintf("Invalid cache entry state: %s", s)) } @@ -288,22 +285,11 @@ func (n *neighborCache) handleConfirmation(addr tcpip.Address, linkAddr tcpip.Li entry.mu.Lock() entry.handleConfirmationLocked(linkAddr, flags) entry.mu.Unlock() - } - // The confirmation SHOULD be silently discarded if the recipient did not - // initiate any communication with the target. This is indicated if there is - // no matching entry for the remote address. -} - -// handleUpperLevelConfirmation processes a confirmation of reachablity from -// some protocol that operates at a layer above the IP/link layer. -func (n *neighborCache) handleUpperLevelConfirmation(addr tcpip.Address) { - n.mu.RLock() - entry, ok := n.mu.cache[addr] - n.mu.RUnlock() - if ok { - entry.mu.Lock() - entry.handleUpperLevelConfirmationLocked() - entry.mu.Unlock() + } else { + // The confirmation SHOULD be silently discarded if the recipient did not + // initiate any communication with the target. This is indicated if there is + // no matching entry for the remote address. + n.nic.stats.neighbor.droppedConfirmationForNoninitiatedNeighbor.Increment() } } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache_mutex.go new file mode 100644 index 000000000..290e48b54 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_cache_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type neighborCacheRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var neighborCachelockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type neighborCachelockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *neighborCacheRWMutex) Lock() { + locking.AddGLock(neighborCacheprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *neighborCacheRWMutex) NestedLock(i neighborCachelockNameIndex) { + locking.AddGLock(neighborCacheprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *neighborCacheRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(neighborCacheprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *neighborCacheRWMutex) NestedUnlock(i neighborCachelockNameIndex) { + m.mu.Unlock() + locking.DelGLock(neighborCacheprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *neighborCacheRWMutex) RLock() { + locking.AddGLock(neighborCacheprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *neighborCacheRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(neighborCacheprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *neighborCacheRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *neighborCacheRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *neighborCacheRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var neighborCacheprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func neighborCacheinitLockNames() {} + +func init() { + neighborCacheinitLockNames() + neighborCacheprefixIndex = locking.NewMutexClass(reflect.TypeOf(neighborCacheRWMutex{}), neighborCachelockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry.go index 2a8f7deb4..d194e369c 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry.go @@ -16,7 +16,6 @@ package stack import ( "fmt" - "sync" "time" "gvisor.dev/gvisor/pkg/tcpip" @@ -97,7 +96,7 @@ type neighborEntry struct { nudState *NUDState mu struct { - sync.RWMutex + neighborEntryRWMutex neigh NeighborEntry @@ -232,6 +231,8 @@ func (e *neighborEntry) cancelTimerLocked() { func (e *neighborEntry) removeLocked() { e.mu.neigh.UpdatedAt = e.cache.nic.stack.clock.NowMonotonic() e.dispatchRemoveEventLocked() + // Set state to unknown to invalidate this entry if it's cached in a Route. + e.setStateLocked(Unknown) e.cancelTimerLocked() // TODO(https://gvisor.dev/issues/5583): test the case where this function is // called during resolution; that can happen in at least these scenarios: @@ -504,6 +505,7 @@ func (e *neighborEntry) handleConfirmationLocked(linkAddr tcpip.LinkAddress, fla // "If the link layer has addresses and no Target Link-Layer Address // option is included, the receiving node SHOULD silently discard the // received advertisement." - RFC 4861 section 7.2.5 + e.cache.nic.stats.neighbor.droppedInvalidLinkAddressConfirmations.Increment() break } @@ -567,8 +569,8 @@ func (e *neighborEntry) handleConfirmationLocked(linkAddr tcpip.LinkAddress, fla // // TODO(gvisor.dev/issue/4085): Remove the special casing we do for IPv6 // here. - ep, ok := e.cache.nic.networkEndpoints[header.IPv6ProtocolNumber] - if !ok { + ep := e.cache.nic.getNetworkEndpoint(header.IPv6ProtocolNumber) + if ep == nil { panic(fmt.Sprintf("have a neighbor entry for an IPv6 router but no IPv6 network endpoint")) } @@ -586,24 +588,59 @@ func (e *neighborEntry) handleConfirmationLocked(linkAddr tcpip.LinkAddress, fla } } -// handleUpperLevelConfirmationLocked processes an incoming upper-level protocol +// handleUpperLevelConfirmation processes an incoming upper-level protocol // (e.g. TCP acknowledgements) reachability confirmation. -// -// Precondition: e.mu MUST be locked. -func (e *neighborEntry) handleUpperLevelConfirmationLocked() { - switch e.mu.neigh.State { - case Stale, Delay, Probe: - e.setStateLocked(Reachable) - e.dispatchChangeEventLocked() +func (e *neighborEntry) handleUpperLevelConfirmation() { + tryHandleConfirmation := func() bool { + switch e.mu.neigh.State { + case Stale, Delay, Probe: + return true + case Reachable: + // Avoid setStateLocked; Timer.Reset is cheaper. + // + // Note that setting the timer does not need to be protected by the + // entry's write lock since we do not modify the timer pointer, but the + // time the timer should fire. The timer should have internal locks to + // synchronize timer resets changes with the clock. + e.mu.timer.timer.Reset(e.nudState.ReachableTime()) + return false + case Unknown, Incomplete, Unreachable, Static: + // Do nothing + return false + default: + panic(fmt.Sprintf("Invalid cache entry state: %s", e.mu.neigh.State)) + } + } - case Reachable: - // Avoid setStateLocked; Timer.Reset is cheaper. - e.mu.timer.timer.Reset(e.nudState.ReachableTime()) + e.mu.RLock() + needsTransition := tryHandleConfirmation() + e.mu.RUnlock() + if !needsTransition { + return + } - case Unknown, Incomplete, Unreachable, Static: - // Do nothing + // We need to transition the neighbor to Reachable so take the write lock and + // perform the transition, but only if we still need the transition since the + // state could have changed since we dropped the read lock above. + e.mu.Lock() + defer e.mu.Unlock() + if needsTransition := tryHandleConfirmation(); needsTransition { + e.setStateLocked(Reachable) + e.dispatchChangeEventLocked() + } +} +// getRemoteLinkAddress returns the entry's link address and whether that link +// address is valid. +func (e *neighborEntry) getRemoteLinkAddress() (tcpip.LinkAddress, bool) { + e.mu.RLock() + defer e.mu.RUnlock() + switch e.mu.neigh.State { + case Reachable, Static, Delay, Probe: + return e.mu.neigh.LinkAddr, true + case Unknown, Incomplete, Unreachable, Stale: + return "", false default: - panic(fmt.Sprintf("Invalid cache entry state: %s", e.mu.neigh.State)) + panic(fmt.Sprintf("invalid state for neighbor entry %v: %v", e.mu.neigh, e.mu.neigh.State)) } } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry_mutex.go new file mode 100644 index 000000000..f8be1dae8 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/neighbor_entry_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type neighborEntryRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var neighborEntrylockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type neighborEntrylockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *neighborEntryRWMutex) Lock() { + locking.AddGLock(neighborEntryprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *neighborEntryRWMutex) NestedLock(i neighborEntrylockNameIndex) { + locking.AddGLock(neighborEntryprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *neighborEntryRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(neighborEntryprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *neighborEntryRWMutex) NestedUnlock(i neighborEntrylockNameIndex) { + m.mu.Unlock() + locking.DelGLock(neighborEntryprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *neighborEntryRWMutex) RLock() { + locking.AddGLock(neighborEntryprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *neighborEntryRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(neighborEntryprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *neighborEntryRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *neighborEntryRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *neighborEntryRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var neighborEntryprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func neighborEntryinitLockNames() {} + +func init() { + neighborEntryinitLockNames() + neighborEntryprefixIndex = locking.NewMutexClass(reflect.TypeOf(neighborEntryRWMutex{}), neighborEntrylockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go index 1537582b6..38b71f67a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go @@ -19,7 +19,6 @@ import ( "reflect" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -30,15 +29,6 @@ type linkResolver struct { neigh neighborCache } -func (l *linkResolver) getNeighborLinkAddress(addr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, tcpip.Error) { - entry, ch, err := l.neigh.entry(addr, localAddr, onResolve) - return entry.LinkAddr, ch, err -} - -func (l *linkResolver) confirmReachable(addr tcpip.Address) { - l.neigh.handleUpperLevelConfirmation(addr) -} - var _ NetworkInterface = (*nic)(nil) var _ NetworkDispatcher = (*nic)(nil) @@ -54,30 +44,31 @@ type nic struct { stats sharedStats + // mu protects annotated fields below. + mu nicRWMutex + // The network endpoints themselves may be modified by calling the interface's // methods, but the map reference and entries must be constant. + // +checklocks:mu networkEndpoints map[tcpip.NetworkProtocolNumber]NetworkEndpoint linkAddrResolvers map[tcpip.NetworkProtocolNumber]*linkResolver duplicateAddressDetectors map[tcpip.NetworkProtocolNumber]DuplicateAddressDetector - // enabled is set to 1 when the NIC is enabled and 0 when it is disabled. - enabled atomicbitops.Uint32 + // enabled indicates whether the NIC is enabled. + enabled atomicbitops.Bool + + // spoofing indicates whether the NIC is spoofing. + spoofing atomicbitops.Bool + + // promiscuous indicates whether the NIC is promiscuous. + promiscuous atomicbitops.Bool // linkResQueue holds packets that are waiting for link resolution to // complete. linkResQueue packetsPendingLinkResolution - // mu protects annotated fields below. - mu sync.RWMutex - - // +checklocks:mu - spoofing bool - - // +checklocks:mu - promiscuous bool - // packetEPsMu protects annotated fields below. - packetEPsMu sync.RWMutex + packetEPsMu packetEPsRWMutex // eps is protected by the mutex, but the values contained in it are not. // @@ -85,6 +76,8 @@ type nic struct { packetEPs map[tcpip.NetworkProtocolNumber]*packetEndpointList qDisc QueueingDiscipline + + gro groDispatcher } // makeNICStats initializes the NIC statistics and associates them to the global @@ -97,7 +90,7 @@ func makeNICStats(global tcpip.NICStats) sharedStats { } type packetEndpointList struct { - mu sync.RWMutex + mu packetEndpointListRWMutex // eps is protected by mu, but the contained PacketEndpoint values are not. // @@ -146,7 +139,7 @@ type delegatingQueueingDiscipline struct { func (*delegatingQueueingDiscipline) Close() {} // WritePacket passes the packet through to the underlying LinkWriter's WritePackets. -func (qDisc *delegatingQueueingDiscipline) WritePacket(pkt *PacketBuffer) tcpip.Error { +func (qDisc *delegatingQueueingDiscipline) WritePacket(pkt PacketBufferPtr) tcpip.Error { var pkts PacketBufferList pkts.PushBack(pkt) _, err := qDisc.LinkWriter.WritePackets(pkts) @@ -208,28 +201,28 @@ func newNIC(stack *Stack, id tcpip.NICID, ep LinkEndpoint, opts NICOptions) *nic } } + nic.gro.init(opts.GROTimeout) nic.NetworkLinkEndpoint.Attach(nic) return nic } func (n *nic) getNetworkEndpoint(proto tcpip.NetworkProtocolNumber) NetworkEndpoint { + n.mu.RLock() + defer n.mu.RUnlock() return n.networkEndpoints[proto] } // Enabled implements NetworkInterface. func (n *nic) Enabled() bool { - return n.enabled.Load() == 1 + return n.enabled.Load() } // setEnabled sets the enabled status for the NIC. // // Returns true if the enabled status was updated. func (n *nic) setEnabled(v bool) bool { - if v { - return n.enabled.Swap(1) == 0 - } - return n.enabled.Swap(0) == 1 + return n.enabled.Swap(v) != v } // disable disables n. @@ -237,15 +230,15 @@ func (n *nic) setEnabled(v bool) bool { // It undoes the work done by enable. func (n *nic) disable() { n.mu.Lock() + defer n.mu.Unlock() n.disableLocked() - n.mu.Unlock() } // disableLocked disables n. // // It undoes the work done by enable. // -// n MUST be locked. +// +checklocks:n.mu func (n *nic) disableLocked() { if !n.Enabled() { return @@ -306,7 +299,6 @@ func (n *nic) enable() tcpip.Error { // stack. func (n *nic) remove() tcpip.Error { n.mu.Lock() - defer n.mu.Unlock() n.disableLocked() @@ -314,7 +306,13 @@ func (n *nic) remove() tcpip.Error { ep.Close() } - // drain and drop any packets pending link resolution. + n.mu.Unlock() + + // Shutdown GRO. + n.gro.close() + + // Drain and drop any packets pending link resolution. + // We must not hold n.mu here. n.linkResQueue.cancel() // Prevent packets from going down to the link before shutting the link down. @@ -326,17 +324,12 @@ func (n *nic) remove() tcpip.Error { // setPromiscuousMode enables or disables promiscuous mode. func (n *nic) setPromiscuousMode(enable bool) { - n.mu.Lock() - n.promiscuous = enable - n.mu.Unlock() + n.promiscuous.Store(enable) } // Promiscuous implements NetworkInterface. func (n *nic) Promiscuous() bool { - n.mu.RLock() - rv := n.promiscuous - n.mu.RUnlock() - return rv + return n.promiscuous.Load() } // IsLoopback implements NetworkInterface. @@ -345,7 +338,7 @@ func (n *nic) IsLoopback() bool { } // WritePacket implements NetworkEndpoint. -func (n *nic) WritePacket(r *Route, pkt *PacketBuffer) tcpip.Error { +func (n *nic) WritePacket(r *Route, pkt PacketBufferPtr) tcpip.Error { routeInfo, _, err := r.resolvedFields(nil) switch err.(type) { case nil: @@ -376,7 +369,7 @@ func (n *nic) WritePacket(r *Route, pkt *PacketBuffer) tcpip.Error { } // WritePacketToRemote implements NetworkInterface. -func (n *nic) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, pkt *PacketBuffer) tcpip.Error { +func (n *nic) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, pkt PacketBufferPtr) tcpip.Error { pkt.EgressRoute = RouteInfo{ routeInfo: routeInfo{ NetProto: pkt.NetworkProtocolNumber, @@ -387,12 +380,12 @@ func (n *nic) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, pkt *PacketB return n.writePacket(pkt) } -func (n *nic) writePacket(pkt *PacketBuffer) tcpip.Error { +func (n *nic) writePacket(pkt PacketBufferPtr) tcpip.Error { n.NetworkLinkEndpoint.AddHeader(pkt) return n.writeRawPacket(pkt) } -func (n *nic) writeRawPacket(pkt *PacketBuffer) tcpip.Error { +func (n *nic) writeRawPacket(pkt PacketBufferPtr) tcpip.Error { if err := n.qDisc.WritePacket(pkt); err != nil { if _, ok := err.(*tcpip.ErrNoBufferSpace); ok { n.stats.txPacketsDroppedNoBufferSpace.Increment() @@ -407,23 +400,19 @@ func (n *nic) writeRawPacket(pkt *PacketBuffer) tcpip.Error { // setSpoofing enables or disables address spoofing. func (n *nic) setSpoofing(enable bool) { - n.mu.Lock() - n.spoofing = enable - n.mu.Unlock() + n.spoofing.Store(enable) } // Spoofing implements NetworkInterface. func (n *nic) Spoofing() bool { - n.mu.RLock() - defer n.mu.RUnlock() - return n.spoofing + return n.spoofing.Load() } // primaryAddress returns an address that can be used to communicate with // remoteAddr. func (n *nic) primaryEndpoint(protocol tcpip.NetworkProtocolNumber, remoteAddr tcpip.Address) AssignableAddressEndpoint { - ep, ok := n.networkEndpoints[protocol] - if !ok { + ep := n.getNetworkEndpoint(protocol) + if ep == nil { return nil } @@ -432,11 +421,7 @@ func (n *nic) primaryEndpoint(protocol tcpip.NetworkProtocolNumber, remoteAddr t return nil } - n.mu.RLock() - spoofing := n.spoofing - n.mu.RUnlock() - - return addressableEndpoint.AcquireOutgoingPrimaryAddress(remoteAddr, spoofing) + return addressableEndpoint.AcquireOutgoingPrimaryAddress(remoteAddr, n.Spoofing()) } type getAddressBehaviour int @@ -480,23 +465,21 @@ func (n *nic) findEndpoint(protocol tcpip.NetworkProtocolNumber, address tcpip.A // If the address is the IPv4 broadcast address for an endpoint's network, that // endpoint will be returned. func (n *nic) getAddressOrCreateTemp(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, peb PrimaryEndpointBehavior, tempRef getAddressBehaviour) AssignableAddressEndpoint { - n.mu.RLock() var spoofingOrPromiscuous bool switch tempRef { case spoofing: - spoofingOrPromiscuous = n.spoofing + spoofingOrPromiscuous = n.Spoofing() case promiscuous: - spoofingOrPromiscuous = n.promiscuous + spoofingOrPromiscuous = n.Promiscuous() } - n.mu.RUnlock() return n.getAddressOrCreateTempInner(protocol, address, spoofingOrPromiscuous, peb) } // getAddressOrCreateTempInner is like getAddressEpOrCreateTemp except a boolean // is passed to indicate whether or not we should generate temporary endpoints. func (n *nic) getAddressOrCreateTempInner(protocol tcpip.NetworkProtocolNumber, address tcpip.Address, createTemp bool, peb PrimaryEndpointBehavior) AssignableAddressEndpoint { - ep, ok := n.networkEndpoints[protocol] - if !ok { + ep := n.getNetworkEndpoint(protocol) + if ep == nil { return nil } @@ -511,8 +494,8 @@ func (n *nic) getAddressOrCreateTempInner(protocol tcpip.NetworkProtocolNumber, // addAddress adds a new address to n, so that it starts accepting packets // targeted at the given address (and network protocol). func (n *nic) addAddress(protocolAddress tcpip.ProtocolAddress, properties AddressProperties) tcpip.Error { - ep, ok := n.networkEndpoints[protocolAddress.Protocol] - if !ok { + ep := n.getNetworkEndpoint(protocolAddress.Protocol) + if ep == nil { return &tcpip.ErrUnknownProtocol{} } @@ -532,6 +515,8 @@ func (n *nic) addAddress(protocolAddress tcpip.ProtocolAddress, properties Addre // allPermanentAddresses returns all permanent addresses associated with // this NIC. func (n *nic) allPermanentAddresses() []tcpip.ProtocolAddress { + n.mu.RLock() + defer n.mu.RUnlock() var addrs []tcpip.ProtocolAddress for p, ep := range n.networkEndpoints { addressableEndpoint, ok := ep.(AddressableEndpoint) @@ -548,6 +533,8 @@ func (n *nic) allPermanentAddresses() []tcpip.ProtocolAddress { // primaryAddresses returns the primary addresses associated with this NIC. func (n *nic) primaryAddresses() []tcpip.ProtocolAddress { + n.mu.RLock() + defer n.mu.RUnlock() var addrs []tcpip.ProtocolAddress for p, ep := range n.networkEndpoints { addressableEndpoint, ok := ep.(AddressableEndpoint) @@ -564,8 +551,8 @@ func (n *nic) primaryAddresses() []tcpip.ProtocolAddress { // PrimaryAddress implements NetworkInterface. func (n *nic) PrimaryAddress(proto tcpip.NetworkProtocolNumber) (tcpip.AddressWithPrefix, tcpip.Error) { - ep, ok := n.networkEndpoints[proto] - if !ok { + ep := n.getNetworkEndpoint(proto) + if ep == nil { return tcpip.AddressWithPrefix{}, &tcpip.ErrUnknownProtocol{} } @@ -579,6 +566,8 @@ func (n *nic) PrimaryAddress(proto tcpip.NetworkProtocolNumber) (tcpip.AddressWi // removeAddress removes an address from n. func (n *nic) removeAddress(addr tcpip.Address) tcpip.Error { + n.mu.RLock() + defer n.mu.RUnlock() for _, ep := range n.networkEndpoints { addressableEndpoint, ok := ep.(AddressableEndpoint) if !ok { @@ -597,6 +586,8 @@ func (n *nic) removeAddress(addr tcpip.Address) tcpip.Error { } func (n *nic) setAddressLifetimes(addr tcpip.Address, lifetimes AddressLifetimes) tcpip.Error { + n.mu.RLock() + defer n.mu.RUnlock() for _, ep := range n.networkEndpoints { ep, ok := ep.(AddressableEndpoint) if !ok { @@ -625,7 +616,7 @@ func (n *nic) getLinkAddress(addr, localAddr tcpip.Address, protocol tcpip.Netwo return nil } - _, _, err := linkRes.getNeighborLinkAddress(addr, localAddr, onResolve) + _, _, err := linkRes.neigh.entry(addr, localAddr, onResolve) return err } @@ -674,8 +665,8 @@ func (n *nic) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address // as an MLD packet's source address must be a link-local address as // outlined in RFC 3810 section 5. - ep, ok := n.networkEndpoints[protocol] - if !ok { + ep := n.getNetworkEndpoint(protocol) + if ep == nil { return &tcpip.ErrNotSupported{} } @@ -690,8 +681,8 @@ func (n *nic) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address // leaveGroup decrements the count for the given multicast address, and when it // reaches zero removes the endpoint for this address. func (n *nic) leaveGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error { - ep, ok := n.networkEndpoints[protocol] - if !ok { + ep := n.getNetworkEndpoint(protocol) + if ep == nil { return &tcpip.ErrNotSupported{} } @@ -705,6 +696,8 @@ func (n *nic) leaveGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Addres // isInGroup returns true if n has joined the multicast group addr. func (n *nic) isInGroup(addr tcpip.Address) bool { + n.mu.RLock() + defer n.mu.RUnlock() for _, ep := range n.networkEndpoints { gep, ok := ep.(GroupAddressableEndpoint) if !ok { @@ -722,7 +715,7 @@ func (n *nic) isInGroup(addr tcpip.Address) bool { // DeliverNetworkPacket finds the appropriate network protocol endpoint and // hands the packet over for further processing. This function is called when // the NIC receives a packet from the link endpoint. -func (n *nic) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) { +func (n *nic) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr) { enabled := n.Enabled() // If the NIC is not yet enabled, don't receive any packets. if !enabled { @@ -734,27 +727,27 @@ func (n *nic) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *Pa n.stats.rx.packets.Increment() n.stats.rx.bytes.IncrementBy(uint64(pkt.Data().Size())) - networkEndpoint, ok := n.networkEndpoints[protocol] - if !ok { + networkEndpoint := n.getNetworkEndpoint(protocol) + if networkEndpoint == nil { n.stats.unknownL3ProtocolRcvdPacketCounts.Increment(uint64(protocol)) return } - pkt.RXTransportChecksumValidated = n.NetworkLinkEndpoint.Capabilities()&CapabilityRXChecksumOffload != 0 + pkt.RXChecksumValidated = n.NetworkLinkEndpoint.Capabilities()&CapabilityRXChecksumOffload != 0 - networkEndpoint.HandlePacket(pkt) + n.gro.dispatch(pkt, protocol, networkEndpoint) } -func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer, incoming bool) { +func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr, incoming bool) { // Deliver to interested packet endpoints without holding NIC lock. - var packetEPPkt *PacketBuffer + var packetEPPkt PacketBufferPtr defer func() { - if packetEPPkt != nil { + if !packetEPPkt.IsNil() { packetEPPkt.DecRef() } }() deliverPacketEPs := func(ep PacketEndpoint) { - if packetEPPkt == nil { + if packetEPPkt.IsNil() { // Packet endpoints hold the full packet. // // We perform a deep copy because higher-level endpoints may point to @@ -802,7 +795,7 @@ func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *Packe // DeliverTransportPacket delivers the packets to the appropriate transport // protocol endpoint. -func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) TransportPacketDisposition { +func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt PacketBufferPtr) TransportPacketDisposition { state, ok := n.stack.transportProtocols[protocol] if !ok { n.stats.unknownL4ProtocolRcvdPacketCounts.Increment(uint64(protocol)) @@ -862,7 +855,7 @@ func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt } // DeliverTransportError implements TransportDispatcher. -func (n *nic) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt *PacketBuffer) { +func (n *nic) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt PacketBufferPtr) { state, ok := n.stack.transportProtocols[trans] if !ok { return @@ -890,7 +883,7 @@ func (n *nic) DeliverTransportError(local, remote tcpip.Address, net tcpip.Netwo } // DeliverRawPacket implements TransportDispatcher. -func (n *nic) DeliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) { +func (n *nic) DeliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt PacketBufferPtr) { // For ICMPv4 only we validate the header length for compatibility with // raw(7) ICMP_FILTER. The same check is made in Linux here: // https://github.com/torvalds/linux/blob/70585216/net/ipv4/raw.c#L189. @@ -965,10 +958,7 @@ func (n *nic) unregisterPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep // packet. It requires the endpoint to not be marked expired (i.e., its address // has been removed) unless the NIC is in spoofing mode, or temporary. func (n *nic) isValidForOutgoing(ep AssignableAddressEndpoint) bool { - n.mu.RLock() - spoofing := n.spoofing - n.mu.RUnlock() - return n.Enabled() && ep.IsAssigned(spoofing) + return n.Enabled() && ep.IsAssigned(n.Spoofing()) } // HandleNeighborProbe implements NetworkInterface. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_mutex.go new file mode 100644 index 000000000..95bfb3010 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type nicRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var niclockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type niclockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *nicRWMutex) Lock() { + locking.AddGLock(nicprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *nicRWMutex) NestedLock(i niclockNameIndex) { + locking.AddGLock(nicprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *nicRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(nicprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *nicRWMutex) NestedUnlock(i niclockNameIndex) { + m.mu.Unlock() + locking.DelGLock(nicprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *nicRWMutex) RLock() { + locking.AddGLock(nicprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *nicRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(nicprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *nicRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *nicRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *nicRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var nicprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func nicinitLockNames() {} + +func init() { + nicinitLockNames() + nicprefixIndex = locking.NewMutexClass(reflect.TypeOf(nicRWMutex{}), niclockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go index e94ea572f..aa336545b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go @@ -40,11 +40,15 @@ func (m *multiCounterNICPacketStats) init(a, b *tcpip.NICPacketStats) { // LINT.IfChange(multiCounterNICNeighborStats) type multiCounterNICNeighborStats struct { - unreachableEntryLookups tcpip.MultiCounterStat + unreachableEntryLookups tcpip.MultiCounterStat + droppedConfirmationForNoninitiatedNeighbor tcpip.MultiCounterStat + droppedInvalidLinkAddressConfirmations tcpip.MultiCounterStat } func (m *multiCounterNICNeighborStats) init(a, b *tcpip.NICNeighborStats) { m.unreachableEntryLookups.Init(a.UnreachableEntryLookups, b.UnreachableEntryLookups) + m.droppedConfirmationForNoninitiatedNeighbor.Init(a.DroppedConfirmationForNoninitiatedNeighbor, b.DroppedConfirmationForNoninitiatedNeighbor) + m.droppedInvalidLinkAddressConfirmations.Init(a.DroppedInvalidLinkAddressConfirmations, b.DroppedInvalidLinkAddressConfirmations) } // LINT.ThenChange(../tcpip.go:NICNeighborStats) diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go index f92f5b0a4..8cf77616b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go @@ -34,8 +34,8 @@ const ( ) var pkPool = sync.Pool{ - New: func() interface{} { - return &PacketBuffer{} + New: func() any { + return &packetBuffer{} }, } @@ -58,7 +58,15 @@ type PacketBufferOptions struct { OnRelease func() } -// A PacketBuffer contains all the data of a network packet. +// PacketBufferPtr is a pointer to a PacketBuffer. +// +// +stateify savable +type PacketBufferPtr struct { + // packetBuffer is the underlying packet buffer. + *packetBuffer +} + +// A packetBuffer contains all the data of a network packet. // // As a PacketBuffer traverses up the stack, it may be necessary to pass it to // multiple endpoints. @@ -100,7 +108,7 @@ type PacketBufferOptions struct { // starting offset of each header in `buf`. // // +stateify savable -type PacketBuffer struct { +type packetBuffer struct { _ sync.NoCopy packetBufferRefs @@ -154,9 +162,9 @@ type PacketBuffer struct { // NICID is the ID of the last interface the network packet was handled at. NICID tcpip.NICID - // RXTransportChecksumValidated indicates that transport checksum verification - // may be safely skipped. - RXTransportChecksumValidated bool + // RXChecksumValidated indicates that checksum verification may be + // safely skipped. + RXChecksumValidated bool // NetworkPacketInfo holds an incoming packet's network-layer information. NetworkPacketInfo NetworkPacketInfo @@ -169,8 +177,8 @@ type PacketBuffer struct { } // NewPacketBuffer creates a new PacketBuffer with opts. -func NewPacketBuffer(opts PacketBufferOptions) *PacketBuffer { - pk := pkPool.Get().(*PacketBuffer) +func NewPacketBuffer(opts PacketBufferOptions) PacketBufferPtr { + pk := pkPool.Get().(*packetBuffer) pk.reset() if opts.ReserveHeaderBytes != 0 { v := bufferv2.NewViewSize(opts.ReserveHeaderBytes) @@ -183,47 +191,52 @@ func NewPacketBuffer(opts PacketBufferOptions) *PacketBuffer { pk.NetworkPacketInfo.IsForwardedPacket = opts.IsForwardedPacket pk.onRelease = opts.OnRelease pk.InitRefs() - return pk + return PacketBufferPtr{ + packetBuffer: pk, + } } // IncRef increments the PacketBuffer's refcount. -func (pk *PacketBuffer) IncRef() *PacketBuffer { +func (pk PacketBufferPtr) IncRef() PacketBufferPtr { pk.packetBufferRefs.IncRef() - return pk + return PacketBufferPtr{ + packetBuffer: pk.packetBuffer, + } } // DecRef decrements the PacketBuffer's refcount. If the refcount is // decremented to zero, the PacketBuffer is returned to the PacketBuffer // pool. -func (pk *PacketBuffer) DecRef() { +func (pk *PacketBufferPtr) DecRef() { pk.packetBufferRefs.DecRef(func() { if pk.onRelease != nil { pk.onRelease() } pk.buf.Release() - pkPool.Put(pk) + pkPool.Put(pk.packetBuffer) }) + pk.packetBuffer = nil } -func (pk *PacketBuffer) reset() { - *pk = PacketBuffer{} +func (pk *packetBuffer) reset() { + *pk = packetBuffer{} } // ReservedHeaderBytes returns the number of bytes initially reserved for // headers. -func (pk *PacketBuffer) ReservedHeaderBytes() int { +func (pk PacketBufferPtr) ReservedHeaderBytes() int { return pk.reserved } // AvailableHeaderBytes returns the number of bytes currently available for // headers. This is relevant to PacketHeader.Push method only. -func (pk *PacketBuffer) AvailableHeaderBytes() int { +func (pk PacketBufferPtr) AvailableHeaderBytes() int { return pk.reserved - pk.pushed } // VirtioNetHeader returns the handle to virtio-layer header. -func (pk *PacketBuffer) VirtioNetHeader() PacketHeader { +func (pk PacketBufferPtr) VirtioNetHeader() PacketHeader { return PacketHeader{ pk: pk, typ: virtioNetHeader, @@ -231,7 +244,7 @@ func (pk *PacketBuffer) VirtioNetHeader() PacketHeader { } // LinkHeader returns the handle to link-layer header. -func (pk *PacketBuffer) LinkHeader() PacketHeader { +func (pk PacketBufferPtr) LinkHeader() PacketHeader { return PacketHeader{ pk: pk, typ: linkHeader, @@ -239,7 +252,7 @@ func (pk *PacketBuffer) LinkHeader() PacketHeader { } // NetworkHeader returns the handle to network-layer header. -func (pk *PacketBuffer) NetworkHeader() PacketHeader { +func (pk PacketBufferPtr) NetworkHeader() PacketHeader { return PacketHeader{ pk: pk, typ: networkHeader, @@ -247,7 +260,7 @@ func (pk *PacketBuffer) NetworkHeader() PacketHeader { } // TransportHeader returns the handle to transport-layer header. -func (pk *PacketBuffer) TransportHeader() PacketHeader { +func (pk PacketBufferPtr) TransportHeader() PacketHeader { return PacketHeader{ pk: pk, typ: transportHeader, @@ -255,28 +268,28 @@ func (pk *PacketBuffer) TransportHeader() PacketHeader { } // HeaderSize returns the total size of all headers in bytes. -func (pk *PacketBuffer) HeaderSize() int { +func (pk PacketBufferPtr) HeaderSize() int { return pk.pushed + pk.consumed } // Size returns the size of packet in bytes. -func (pk *PacketBuffer) Size() int { +func (pk PacketBufferPtr) Size() int { return int(pk.buf.Size()) - pk.headerOffset() } // MemSize returns the estimation size of the pk in memory, including backing // buffer data. -func (pk *PacketBuffer) MemSize() int { +func (pk PacketBufferPtr) MemSize() int { return int(pk.buf.Size()) + PacketBufferStructSize } // Data returns the handle to data portion of pk. -func (pk *PacketBuffer) Data() PacketData { +func (pk PacketBufferPtr) Data() PacketData { return PacketData{pk: pk} } // AsSlices returns the underlying storage of the whole packet. -func (pk *PacketBuffer) AsSlices() [][]byte { +func (pk PacketBufferPtr) AsSlices() [][]byte { var views [][]byte offset := pk.headerOffset() pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *bufferv2.View) { @@ -287,7 +300,7 @@ func (pk *PacketBuffer) AsSlices() [][]byte { // ToBuffer returns a caller-owned copy of the underlying storage of the whole // packet. -func (pk *PacketBuffer) ToBuffer() bufferv2.Buffer { +func (pk PacketBufferPtr) ToBuffer() bufferv2.Buffer { b := pk.buf.Clone() b.TrimFront(int64(pk.headerOffset())) return b @@ -295,7 +308,7 @@ func (pk *PacketBuffer) ToBuffer() bufferv2.Buffer { // ToView returns a caller-owned copy of the underlying storage of the whole // packet as a view. -func (pk *PacketBuffer) ToView() *bufferv2.View { +func (pk PacketBufferPtr) ToView() *bufferv2.View { p := bufferv2.NewView(int(pk.buf.Size())) offset := pk.headerOffset() pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *bufferv2.View) { @@ -304,19 +317,19 @@ func (pk *PacketBuffer) ToView() *bufferv2.View { return p } -func (pk *PacketBuffer) headerOffset() int { +func (pk PacketBufferPtr) headerOffset() int { return pk.reserved - pk.pushed } -func (pk *PacketBuffer) headerOffsetOf(typ headerType) int { +func (pk PacketBufferPtr) headerOffsetOf(typ headerType) int { return pk.reserved + pk.headers[typ].offset } -func (pk *PacketBuffer) dataOffset() int { +func (pk PacketBufferPtr) dataOffset() int { return pk.reserved + pk.consumed } -func (pk *PacketBuffer) push(typ headerType, size int) []byte { +func (pk PacketBufferPtr) push(typ headerType, size int) []byte { h := &pk.headers[typ] if h.length > 0 { panic(fmt.Sprintf("push(%s, %d) called after previous push", typ, size)) @@ -331,7 +344,7 @@ func (pk *PacketBuffer) push(typ headerType, size int) []byte { return view.AsSlice() } -func (pk *PacketBuffer) consume(typ headerType, size int) (v []byte, consumed bool) { +func (pk PacketBufferPtr) consume(typ headerType, size int) (v []byte, consumed bool) { h := &pk.headers[typ] if h.length > 0 { panic(fmt.Sprintf("consume must not be called twice: type %s", typ)) @@ -346,7 +359,7 @@ func (pk *PacketBuffer) consume(typ headerType, size int) (v []byte, consumed bo return view.AsSlice(), true } -func (pk *PacketBuffer) headerView(typ headerType) bufferv2.View { +func (pk PacketBufferPtr) headerView(typ headerType) bufferv2.View { h := &pk.headers[typ] if h.length == 0 { return bufferv2.View{} @@ -360,8 +373,8 @@ func (pk *PacketBuffer) headerView(typ headerType) bufferv2.View { // Clone makes a semi-deep copy of pk. The underlying packet payload is // shared. Hence, no modifications is done to underlying packet payload. -func (pk *PacketBuffer) Clone() *PacketBuffer { - newPk := pkPool.Get().(*PacketBuffer) +func (pk PacketBufferPtr) Clone() PacketBufferPtr { + newPk := pkPool.Get().(*packetBuffer) newPk.reset() newPk.buf = pk.buf.Clone() newPk.reserved = pk.reserved @@ -377,16 +390,18 @@ func (pk *PacketBuffer) Clone() *PacketBuffer { newPk.TransportProtocolNumber = pk.TransportProtocolNumber newPk.PktType = pk.PktType newPk.NICID = pk.NICID - newPk.RXTransportChecksumValidated = pk.RXTransportChecksumValidated + newPk.RXChecksumValidated = pk.RXChecksumValidated newPk.NetworkPacketInfo = pk.NetworkPacketInfo newPk.tuple = pk.tuple newPk.InitRefs() - return newPk + return PacketBufferPtr{ + packetBuffer: newPk, + } } // ReserveHeaderBytes prepends reserved space for headers at the front // of the underlying buf. Can only be called once per packet. -func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) { +func (pk PacketBufferPtr) ReserveHeaderBytes(reserved int) { if pk.reserved != 0 { panic(fmt.Sprintf("ReserveHeaderBytes(...) called on packet with reserved=%d, want reserved=0", pk.reserved)) } @@ -397,7 +412,7 @@ func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) { // Network returns the network header as a header.Network. // // Network should only be called when NetworkHeader has been set. -func (pk *PacketBuffer) Network() header.Network { +func (pk PacketBufferPtr) Network() header.Network { switch netProto := pk.NetworkProtocolNumber; netProto { case header.IPv4ProtocolNumber: return header.IPv4(pk.NetworkHeader().Slice()) @@ -413,15 +428,17 @@ func (pk *PacketBuffer) Network() header.Network { // // See PacketBuffer.Data for details about how a packet buffer holds an inbound // packet. -func (pk *PacketBuffer) CloneToInbound() *PacketBuffer { - newPk := pkPool.Get().(*PacketBuffer) +func (pk PacketBufferPtr) CloneToInbound() PacketBufferPtr { + newPk := pkPool.Get().(*packetBuffer) newPk.reset() newPk.buf = pk.buf.Clone() newPk.InitRefs() // Treat unfilled header portion as reserved. newPk.reserved = pk.AvailableHeaderBytes() newPk.tuple = pk.tuple - return newPk + return PacketBufferPtr{ + packetBuffer: newPk, + } } // DeepCopyForForwarding creates a deep copy of the packet buffer for @@ -429,7 +446,7 @@ func (pk *PacketBuffer) CloneToInbound() *PacketBuffer { // // The returned packet buffer will have the network and transport headers // set if the original packet buffer did. -func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBuffer { +func (pk PacketBufferPtr) DeepCopyForForwarding(reservedHeaderBytes int) PacketBufferPtr { newPk := NewPacketBuffer(PacketBufferOptions{ ReserveHeaderBytes: reservedHeaderBytes, Payload: BufferSince(pk.NetworkHeader()), @@ -457,6 +474,11 @@ func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBu return newPk } +// IsNil returns whether the pointer is logically nil. +func (pk PacketBufferPtr) IsNil() bool { + return pk.packetBuffer == nil +} + // headerInfo stores metadata about a header in a packet. // // +stateify savable @@ -471,7 +493,7 @@ type headerInfo struct { // PacketHeader is a handle object to a header in the underlying packet. type PacketHeader struct { - pk *PacketBuffer + pk PacketBufferPtr typ headerType } @@ -513,7 +535,7 @@ func (h PacketHeader) Consume(size int) (v []byte, consumed bool) { // // +stateify savable type PacketData struct { - pk *PacketBuffer + pk PacketBufferPtr } // PullUp returns a contiguous slice of size bytes from the beginning of d. @@ -591,7 +613,7 @@ func (d PacketData) MergeBuffer(b *bufferv2.Buffer) { // MergeFragment appends the data portion of frag to dst. It modifies // frag and frag should not be used again. -func MergeFragment(dst, frag *PacketBuffer) { +func MergeFragment(dst, frag PacketBufferPtr) { frag.buf.TrimFront(int64(frag.dataOffset())) dst.buf.Merge(&frag.buf) } @@ -651,9 +673,20 @@ func (d PacketData) AsRange() Range { } } +// Checksum returns a checksum over the data payload of the packet. +func (d PacketData) Checksum() uint16 { + return d.pk.buf.Checksum(d.pk.dataOffset()) +} + +// ChecksumAtOffset returns a checksum over the data payload of the packet +// starting from offset. +func (d PacketData) ChecksumAtOffset(offset int) uint16 { + return d.pk.buf.Checksum(offset) +} + // Range represents a contiguous subportion of a PacketBuffer. type Range struct { - pk *PacketBuffer + pk PacketBufferPtr offset int length int } @@ -713,15 +746,6 @@ func (r Range) ToView() *bufferv2.View { return newV } -// Checksum calculates the RFC 1071 checksum for the underlying bytes of r. -func (r Range) Checksum() uint16 { - var c header.Checksumer - r.iterate(func(v *bufferv2.View) { - c.Add(v.AsSlice()) - }) - return c.Checksum() -} - // iterate calls fn for each piece in r. fn is always called with a non-empty // slice. func (r Range) iterate(fn func(*bufferv2.View)) { diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_list.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_list.go index fbd8ab92c..6f09b804d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_list.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_list.go @@ -21,13 +21,13 @@ package stack // // +stateify savable type PacketBufferList struct { - pbs []*PacketBuffer + pbs []PacketBufferPtr } // AsSlice returns a slice containing the packets in the list. // //go:nosplit -func (pl *PacketBufferList) AsSlice() []*PacketBuffer { +func (pl *PacketBufferList) AsSlice() []PacketBufferPtr { return pl.pbs } @@ -37,7 +37,7 @@ func (pl *PacketBufferList) AsSlice() []*PacketBuffer { func (pl *PacketBufferList) Reset() { for i, pb := range pl.pbs { pb.DecRef() - pl.pbs[i] = nil + pl.pbs[i] = PacketBufferPtr{} } pl.pbs = pl.pbs[:0] } @@ -52,7 +52,7 @@ func (pl *PacketBufferList) Len() int { // PushBack inserts the PacketBuffer at the back of the list. // //go:nosplit -func (pl *PacketBufferList) PushBack(pb *PacketBuffer) { +func (pl *PacketBufferList) PushBack(pb PacketBufferPtr) { pl.pbs = append(pl.pbs, pb) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_refs.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_refs.go index 211d0786b..8c205cda9 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_refs.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_refs.go @@ -4,7 +4,7 @@ import ( "fmt" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/refsvfs2" + "gvisor.dev/gvisor/pkg/refs" ) // enableLogging indicates whether reference-related events should be logged (with @@ -15,7 +15,7 @@ const packetBufferenableLogging = false // obj is used to customize logging. Note that we use a pointer to T so that // we do not copy the entire object when passed as a format parameter. -var packetBufferobj *PacketBuffer +var packetBufferobj *packetBuffer // Refs implements refs.RefCounter. It keeps a reference count using atomic // operations and calls the destructor when the count reaches zero. @@ -44,20 +44,20 @@ type packetBufferRefs struct { // checking. func (r *packetBufferRefs) InitRefs() { r.refCount.Store(1) - refsvfs2.Register(r) + refs.Register(r) } -// RefType implements refsvfs2.CheckedObject.RefType. +// RefType implements refs.CheckedObject.RefType. func (r *packetBufferRefs) RefType() string { return fmt.Sprintf("%T", packetBufferobj)[1:] } -// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +// LeakMessage implements refs.CheckedObject.LeakMessage. func (r *packetBufferRefs) LeakMessage() string { return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) } -// LogRefs implements refsvfs2.CheckedObject.LogRefs. +// LogRefs implements refs.CheckedObject.LogRefs. func (r *packetBufferRefs) LogRefs() bool { return packetBufferenableLogging } @@ -74,7 +74,7 @@ func (r *packetBufferRefs) ReadRefs() int64 { func (r *packetBufferRefs) IncRef() { v := r.refCount.Add(1) if packetBufferenableLogging { - refsvfs2.LogIncRef(r, v) + refs.LogIncRef(r, v) } if v <= 1 { panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) @@ -98,7 +98,7 @@ func (r *packetBufferRefs) TryIncRef() bool { v := r.refCount.Add(-speculativeRef + 1) if packetBufferenableLogging { - refsvfs2.LogTryIncRef(r, v) + refs.LogTryIncRef(r, v) } return true } @@ -118,14 +118,14 @@ func (r *packetBufferRefs) TryIncRef() bool { func (r *packetBufferRefs) DecRef(destroy func()) { v := r.refCount.Add(-1) if packetBufferenableLogging { - refsvfs2.LogDecRef(r, v) + refs.LogDecRef(r, v) } switch { case v < 0: panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == 0: - refsvfs2.Unregister(r) + refs.Unregister(r) if destroy != nil { destroy() @@ -135,6 +135,6 @@ func (r *packetBufferRefs) DecRef(destroy func()) { func (r *packetBufferRefs) afterLoad() { if r.ReadRefs() > 0 { - refsvfs2.Register(r) + refs.Register(r) } } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_unsafe.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_unsafe.go index cd151ff0b..f0160ea87 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_unsafe.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer_unsafe.go @@ -17,4 +17,12 @@ package stack import "unsafe" // PacketBufferStructSize is the minimal size of the packet buffer overhead. -const PacketBufferStructSize = int(unsafe.Sizeof(PacketBuffer{})) +const PacketBufferStructSize = int(unsafe.Sizeof(packetBuffer{})) + +// ID returns a unique ID for the underlying storage of the packet. +// +// Two PacketBufferPtrs have the same IDs if and only if they point to the same +// location in memory. +func (pk PacketBufferPtr) ID() uintptr { + return uintptr(unsafe.Pointer(pk.packetBuffer)) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_endpoint_list_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_endpoint_list_mutex.go new file mode 100644 index 000000000..c7e6ef640 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_endpoint_list_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type packetEndpointListRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var packetEndpointListlockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type packetEndpointListlockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *packetEndpointListRWMutex) Lock() { + locking.AddGLock(packetEndpointListprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *packetEndpointListRWMutex) NestedLock(i packetEndpointListlockNameIndex) { + locking.AddGLock(packetEndpointListprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *packetEndpointListRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(packetEndpointListprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *packetEndpointListRWMutex) NestedUnlock(i packetEndpointListlockNameIndex) { + m.mu.Unlock() + locking.DelGLock(packetEndpointListprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *packetEndpointListRWMutex) RLock() { + locking.AddGLock(packetEndpointListprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *packetEndpointListRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(packetEndpointListprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *packetEndpointListRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *packetEndpointListRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *packetEndpointListRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var packetEndpointListprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func packetEndpointListinitLockNames() {} + +func init() { + packetEndpointListinitLockNames() + packetEndpointListprefixIndex = locking.NewMutexClass(reflect.TypeOf(packetEndpointListRWMutex{}), packetEndpointListlockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_eps_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_eps_mutex.go new file mode 100644 index 000000000..2c7d2d9dd --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_eps_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type packetEPsRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var packetEPslockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type packetEPslockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *packetEPsRWMutex) Lock() { + locking.AddGLock(packetEPsprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *packetEPsRWMutex) NestedLock(i packetEPslockNameIndex) { + locking.AddGLock(packetEPsprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *packetEPsRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(packetEPsprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *packetEPsRWMutex) NestedUnlock(i packetEPslockNameIndex) { + m.mu.Unlock() + locking.DelGLock(packetEPsprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *packetEPsRWMutex) RLock() { + locking.AddGLock(packetEPsprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *packetEPsRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(packetEPsprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *packetEPsRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *packetEPsRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *packetEPsRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var packetEPsprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func packetEPsinitLockNames() {} + +func init() { + packetEPsinitLockNames() + packetEPsprefixIndex = locking.NewMutexClass(reflect.TypeOf(packetEPsRWMutex{}), packetEPslockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packets_pending_link_resolution_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packets_pending_link_resolution_mutex.go new file mode 100644 index 000000000..c56608820 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packets_pending_link_resolution_mutex.go @@ -0,0 +1,64 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// Mutex is sync.Mutex with the correctness validator. +type packetsPendingLinkResolutionMutex struct { + mu sync.Mutex +} + +var packetsPendingLinkResolutionprefixIndex *locking.MutexClass + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var packetsPendingLinkResolutionlockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type packetsPendingLinkResolutionlockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *packetsPendingLinkResolutionMutex) Lock() { + locking.AddGLock(packetsPendingLinkResolutionprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *packetsPendingLinkResolutionMutex) NestedLock(i packetsPendingLinkResolutionlockNameIndex) { + locking.AddGLock(packetsPendingLinkResolutionprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *packetsPendingLinkResolutionMutex) Unlock() { + locking.DelGLock(packetsPendingLinkResolutionprefixIndex, -1) + m.mu.Unlock() +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *packetsPendingLinkResolutionMutex) NestedUnlock(i packetsPendingLinkResolutionlockNameIndex) { + locking.DelGLock(packetsPendingLinkResolutionprefixIndex, int(i)) + m.mu.Unlock() +} + +// DO NOT REMOVE: The following function is automatically replaced. +func packetsPendingLinkResolutioninitLockNames() {} + +func init() { + packetsPendingLinkResolutioninitLockNames() + packetsPendingLinkResolutionprefixIndex = locking.NewMutexClass(reflect.TypeOf(packetsPendingLinkResolutionMutex{}), packetsPendingLinkResolutionlockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/pending_packets.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/pending_packets.go index 4b45f6758..0627fb812 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/pending_packets.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/pending_packets.go @@ -17,7 +17,6 @@ package stack import ( "fmt" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" ) @@ -30,7 +29,7 @@ const ( type pendingPacket struct { routeInfo RouteInfo - pkt *PacketBuffer + pkt PacketBufferPtr } // packetsPendingLinkResolution is a queue of packets pending link resolution. @@ -40,7 +39,7 @@ type packetsPendingLinkResolution struct { nic *nic mu struct { - sync.Mutex + packetsPendingLinkResolutionMutex // The packets to send once the resolver completes. // @@ -55,7 +54,7 @@ type packetsPendingLinkResolution struct { } } -func (f *packetsPendingLinkResolution) incrementOutgoingPacketErrors(pkt *PacketBuffer) { +func (f *packetsPendingLinkResolution) incrementOutgoingPacketErrors(pkt PacketBufferPtr) { f.nic.stack.stats.IP.OutgoingPacketErrors.Increment() if ipEndpointStats, ok := f.nic.getNetworkEndpoint(pkt.NetworkProtocolNumber).Stats().(IPNetworkEndpointStats); ok { @@ -114,7 +113,7 @@ func (f *packetsPendingLinkResolution) dequeue(ch <-chan struct{}, linkAddr tcpi // If the maximum number of pending resolutions is reached, the packets // associated with the oldest link resolution will be dequeued as if they failed // link resolution. -func (f *packetsPendingLinkResolution) enqueue(r *Route, pkt *PacketBuffer) tcpip.Error { +func (f *packetsPendingLinkResolution) enqueue(r *Route, pkt PacketBufferPtr) tcpip.Error { f.mu.Lock() // Make sure we attempt resolution while holding f's lock so that we avoid // a race where link resolution completes before we enqueue the packets. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/registration.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/registration.go index e21d94510..cf3bfe3b2 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/registration.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/registration.go @@ -105,12 +105,12 @@ type TransportEndpoint interface { // transport endpoint. It sets the packet buffer's transport header. // // HandlePacket may modify the packet. - HandlePacket(TransportEndpointID, *PacketBuffer) + HandlePacket(TransportEndpointID, PacketBufferPtr) // HandleError is called when the transport endpoint receives an error. // // HandleError takes may modify the packet buffer. - HandleError(TransportError, *PacketBuffer) + HandleError(TransportError, PacketBufferPtr) // Abort initiates an expedited endpoint teardown. It puts the endpoint // in a closed state and frees all resources associated with it. This @@ -138,7 +138,7 @@ type RawTransportEndpoint interface { // layer up. // // HandlePacket may modify the packet. - HandlePacket(*PacketBuffer) + HandlePacket(PacketBufferPtr) } // PacketEndpoint is the interface that needs to be implemented by packet @@ -156,7 +156,7 @@ type PacketEndpoint interface { // should construct its own ethernet header for applications. // // HandlePacket may modify pkt. - HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer) + HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt PacketBufferPtr) } // UnknownDestinationPacketDisposition enumerates the possible return values from @@ -206,7 +206,7 @@ type TransportProtocol interface { // // HandleUnknownDestinationPacket may modify the packet if it handles // the issue. - HandleUnknownDestinationPacket(TransportEndpointID, *PacketBuffer) UnknownDestinationPacketDisposition + HandleUnknownDestinationPacket(TransportEndpointID, PacketBufferPtr) UnknownDestinationPacketDisposition // SetOption allows enabling/disabling protocol specific features. // SetOption returns an error if the option is not supported or the @@ -235,7 +235,7 @@ type TransportProtocol interface { // Parse sets pkt.TransportHeader and trims pkt.Data appropriately. It does // neither and returns false if pkt.Data is too small, i.e. pkt.Data.Size() < // MinimumPacketSize() - Parse(pkt *PacketBuffer) (ok bool) + Parse(pkt PacketBufferPtr) (ok bool) } // TransportPacketDisposition is the result from attempting to deliver a packet @@ -267,18 +267,18 @@ type TransportDispatcher interface { // pkt.NetworkHeader must be set before calling DeliverTransportPacket. // // DeliverTransportPacket may modify the packet. - DeliverTransportPacket(tcpip.TransportProtocolNumber, *PacketBuffer) TransportPacketDisposition + DeliverTransportPacket(tcpip.TransportProtocolNumber, PacketBufferPtr) TransportPacketDisposition // DeliverTransportError delivers an error to the appropriate transport // endpoint. // // DeliverTransportError may modify the packet buffer. - DeliverTransportError(local, remote tcpip.Address, _ tcpip.NetworkProtocolNumber, _ tcpip.TransportProtocolNumber, _ TransportError, _ *PacketBuffer) + DeliverTransportError(local, remote tcpip.Address, _ tcpip.NetworkProtocolNumber, _ tcpip.TransportProtocolNumber, _ TransportError, _ PacketBufferPtr) // DeliverRawPacket delivers a packet to any subscribed raw sockets. // // DeliverRawPacket does NOT take ownership of the packet buffer. - DeliverRawPacket(tcpip.TransportProtocolNumber, *PacketBuffer) + DeliverRawPacket(tcpip.TransportProtocolNumber, PacketBufferPtr) } // PacketLooping specifies where an outbound packet should be sent. @@ -725,13 +725,13 @@ type NetworkInterface interface { CheckLocalAddress(tcpip.NetworkProtocolNumber, tcpip.Address) bool // WritePacketToRemote writes the packet to the given remote link address. - WritePacketToRemote(tcpip.LinkAddress, *PacketBuffer) tcpip.Error + WritePacketToRemote(tcpip.LinkAddress, PacketBufferPtr) tcpip.Error // WritePacket writes a packet through the given route. // // WritePacket may modify the packet buffer. The packet buffer's // network and transport header must be set. - WritePacket(*Route, *PacketBuffer) tcpip.Error + WritePacket(*Route, PacketBufferPtr) tcpip.Error // HandleNeighborProbe processes an incoming neighbor probe (e.g. ARP // request or NDP Neighbor Solicitation). @@ -749,7 +749,7 @@ type NetworkInterface interface { type LinkResolvableNetworkEndpoint interface { // HandleLinkResolutionFailure is called when link resolution prevents the // argument from having been sent. - HandleLinkResolutionFailure(*PacketBuffer) + HandleLinkResolutionFailure(PacketBufferPtr) } // NetworkEndpoint is the interface that needs to be implemented by endpoints @@ -787,17 +787,17 @@ type NetworkEndpoint interface { // WritePacket writes a packet to the given destination address and // protocol. It may modify pkt. pkt.TransportHeader must have // already been set. - WritePacket(r *Route, params NetworkHeaderParams, pkt *PacketBuffer) tcpip.Error + WritePacket(r *Route, params NetworkHeaderParams, pkt PacketBufferPtr) tcpip.Error // WriteHeaderIncludedPacket writes a packet that includes a network // header to the given destination address. It may modify pkt. - WriteHeaderIncludedPacket(r *Route, pkt *PacketBuffer) tcpip.Error + WriteHeaderIncludedPacket(r *Route, pkt PacketBufferPtr) tcpip.Error // HandlePacket is called by the link layer when new packets arrive to // this network endpoint. It sets pkt.NetworkHeader. // // HandlePacket may modify pkt. - HandlePacket(pkt *PacketBuffer) + HandlePacket(pkt PacketBufferPtr) // Close is called when the endpoint is removed from a stack. Close() @@ -896,7 +896,7 @@ type NetworkProtocol interface { // - Whether there is an encapsulated transport protocol payload (e.g. ARP // does not encapsulate anything). // - Whether pkt.Data was large enough to parse and set pkt.NetworkHeader. - Parse(pkt *PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) + Parse(pkt PacketBufferPtr) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) } // UnicastSourceAndMulticastDestination is a tuple that represents a unicast @@ -1012,14 +1012,14 @@ type NetworkDispatcher interface { // If the link-layer has a header, the packet's link header must be populated. // // DeliverNetworkPacket may modify pkt. - DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) + DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr) // DeliverLinkPacket delivers a packet to any interested packet endpoints. // // This method should be called with both incoming and outgoing packets. // // If the link-layer has a header, the packet's link header must be populated. - DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer, incoming bool) + DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr, incoming bool) } // LinkEndpointCapabilities is the type associated with the capabilities @@ -1105,7 +1105,7 @@ type NetworkLinkEndpoint interface { ARPHardwareType() header.ARPHardwareType // AddHeader adds a link layer header to the packet if required. - AddHeader(*PacketBuffer) + AddHeader(PacketBufferPtr) } // QueueingDiscipline provides a queueing strategy for outgoing packets (e.g @@ -1119,7 +1119,7 @@ type QueueingDiscipline interface { // To participate in transparent bridging, a LinkEndpoint implementation // should call eth.Encode with header.EthernetFields.SrcAddr set to // pkg.EgressRoute.LocalLinkAddress if it is provided. - WritePacket(*PacketBuffer) tcpip.Error + WritePacket(PacketBufferPtr) tcpip.Error Close() } @@ -1140,7 +1140,7 @@ type InjectableLinkEndpoint interface { LinkEndpoint // InjectInbound injects an inbound packet. - InjectInbound(protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) + InjectInbound(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr) // InjectOutbound writes a fully formed outbound packet directly to the // link. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route.go index 407d11aef..c7006577f 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route.go @@ -17,7 +17,6 @@ package stack import ( "fmt" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -34,7 +33,7 @@ type Route struct { localAddressNIC *nic // mu protects annotated fields below. - mu sync.RWMutex + mu routeRWMutex // localAddressEndpoint is the local address this route is associated with. // +checklocks:mu @@ -50,6 +49,11 @@ type Route struct { // linkRes is set if link address resolution is enabled for this protocol on // the route's NIC. linkRes *linkResolver + + // neighborEntry is the cached result of fetching a neighbor entry from the + // neighbor cache. + // +checklocks:mu + neighborEntry *neighborEntry } // +stateify savable @@ -390,22 +394,45 @@ func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteIn linkAddressResolutionRequestLocalAddr = r.LocalAddress() } + nEntry := r.getCachedNeighborEntry() + if nEntry != nil { + if addr, ok := nEntry.getRemoteLinkAddress(); ok { + fields.RemoteLinkAddress = addr + if afterResolve != nil { + afterResolve(ResolvedFieldsResult{RouteInfo: fields, Err: nil}) + } + return fields, nil, nil + } + } afterResolveFields := fields - linkAddr, ch, err := r.linkRes.getNeighborLinkAddress(r.nextHop(), linkAddressResolutionRequestLocalAddr, func(r LinkResolutionResult) { + entry, ch, err := r.linkRes.neigh.entry(r.nextHop(), linkAddressResolutionRequestLocalAddr, func(lrr LinkResolutionResult) { if afterResolve != nil { - if r.Err == nil { - afterResolveFields.RemoteLinkAddress = r.LinkAddress + if lrr.Err == nil { + afterResolveFields.RemoteLinkAddress = lrr.LinkAddress } - afterResolve(ResolvedFieldsResult{RouteInfo: afterResolveFields, Err: r.Err}) + afterResolve(ResolvedFieldsResult{RouteInfo: afterResolveFields, Err: lrr.Err}) } }) if err == nil { - fields.RemoteLinkAddress = linkAddr + fields.RemoteLinkAddress, _ = entry.getRemoteLinkAddress() } + r.setCachedNeighborEntry(entry) return fields, ch, err } +func (r *Route) getCachedNeighborEntry() *neighborEntry { + r.mu.RLock() + defer r.mu.RUnlock() + return r.neighborEntry +} + +func (r *Route) setCachedNeighborEntry(entry *neighborEntry) { + r.mu.Lock() + defer r.mu.Unlock() + r.neighborEntry = entry +} + func (r *Route) nextHop() tcpip.Address { if len(r.NextHop()) == 0 { return r.RemoteAddress() @@ -460,7 +487,7 @@ func (r *Route) isValidForOutgoingRLocked() bool { } // WritePacket writes the packet through the given route. -func (r *Route) WritePacket(params NetworkHeaderParams, pkt *PacketBuffer) tcpip.Error { +func (r *Route) WritePacket(params NetworkHeaderParams, pkt PacketBufferPtr) tcpip.Error { if !r.isValidForOutgoing() { return &tcpip.ErrInvalidEndpointState{} } @@ -470,7 +497,7 @@ func (r *Route) WritePacket(params NetworkHeaderParams, pkt *PacketBuffer) tcpip // WriteHeaderIncludedPacket writes a packet already containing a network // header through the given route. -func (r *Route) WriteHeaderIncludedPacket(pkt *PacketBuffer) tcpip.Error { +func (r *Route) WriteHeaderIncludedPacket(pkt PacketBufferPtr) tcpip.Error { if !r.isValidForOutgoing() { return &tcpip.ErrInvalidEndpointState{} } @@ -550,7 +577,7 @@ func (r *Route) IsOutboundBroadcast() bool { // "Reachable" is defined as having full-duplex communication between the // local and remote ends of the route. func (r *Route) ConfirmReachable() { - if r.linkRes != nil { - r.linkRes.confirmReachable(r.nextHop()) + if entry := r.getCachedNeighborEntry(); entry != nil { + entry.handleUpperLevelConfirmation() } } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_mutex.go new file mode 100644 index 000000000..0a5bdd4e2 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type routeRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var routelockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type routelockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *routeRWMutex) Lock() { + locking.AddGLock(routeprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *routeRWMutex) NestedLock(i routelockNameIndex) { + locking.AddGLock(routeprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *routeRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(routeprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *routeRWMutex) NestedUnlock(i routelockNameIndex) { + m.mu.Unlock() + locking.DelGLock(routeprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *routeRWMutex) RLock() { + locking.AddGLock(routeprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *routeRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(routeprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *routeRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *routeRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *routeRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var routeprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func routeinitLockNames() {} + +func init() { + routeinitLockNames() + routeprefixIndex = locking.NewMutexClass(reflect.TypeOf(routeRWMutex{}), routelockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_stack_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_stack_mutex.go new file mode 100644 index 000000000..1c7c92852 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/route_stack_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type routeStackRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var routeStacklockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type routeStacklockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *routeStackRWMutex) Lock() { + locking.AddGLock(routeStackprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *routeStackRWMutex) NestedLock(i routeStacklockNameIndex) { + locking.AddGLock(routeStackprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *routeStackRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(routeStackprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *routeStackRWMutex) NestedUnlock(i routeStacklockNameIndex) { + m.mu.Unlock() + locking.DelGLock(routeStackprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *routeStackRWMutex) RLock() { + locking.AddGLock(routeStackprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *routeStackRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(routeStackprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *routeStackRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *routeStackRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *routeStackRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var routeStackprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func routeStackinitLockNames() {} + +func init() { + routeStackinitLockNames() + routeStackprefixIndex = locking.NewMutexClass(reflect.TypeOf(routeStackRWMutex{}), routeStacklockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack.go index 0f173a10c..892033974 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack.go @@ -32,7 +32,6 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/log" cryptorand "gvisor.dev/gvisor/pkg/rand" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/ports" @@ -46,7 +45,7 @@ const ( type transportProtocolState struct { proto TransportProtocol - defaultHandler func(id TransportEndpointID, pkt *PacketBuffer) bool + defaultHandler func(id TransportEndpointID, pkt PacketBufferPtr) bool } // ResumableEndpoint is an endpoint that needs to be resumed after restore. @@ -85,18 +84,20 @@ type Stack struct { stats tcpip.Stats // routeMu protects annotated fields below. - routeMu sync.RWMutex + routeMu routeStackRWMutex // +checklocks:routeMu routeTable []tcpip.Route - mu sync.RWMutex + mu stackRWMutex + // +checklocks:mu nics map[tcpip.NICID]*nic defaultForwardingEnabled map[tcpip.NetworkProtocolNumber]struct{} // cleanupEndpointsMu protects cleanupEndpoints. - cleanupEndpointsMu sync.Mutex - cleanupEndpoints map[TransportEndpoint]struct{} + cleanupEndpointsMu cleanupEndpointsMutex + // +checklocks:cleanupEndpointsMu + cleanupEndpoints map[TransportEndpoint]struct{} *ports.PortManager @@ -306,7 +307,7 @@ func (t *TransportEndpointInfo) AddrNetProtoLocked(addr tcpip.FullAddress, v6onl case netProto == t.NetProto: case netProto == header.IPv4ProtocolNumber && t.NetProto == header.IPv6ProtocolNumber: if v6only { - return tcpip.FullAddress{}, 0, &tcpip.ErrNoRoute{} + return tcpip.FullAddress{}, 0, &tcpip.ErrHostUnreachable{} } default: return tcpip.FullAddress{}, 0, &tcpip.ErrInvalidEndpointState{} @@ -487,7 +488,7 @@ func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber, // // It must be called only during initialization of the stack. Changing it as the // stack is operating is not supported. -func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(TransportEndpointID, *PacketBuffer) bool) { +func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(TransportEndpointID, PacketBufferPtr) bool) { state := s.transportProtocols[p] if state != nil { state.defaultHandler = h @@ -708,6 +709,33 @@ func (s *Stack) SetPortRange(start uint16, end uint16) tcpip.Error { return s.PortManager.SetPortRange(start, end) } +// GROTimeout returns the GRO timeout. +func (s *Stack) GROTimeout(NICID int32) (time.Duration, tcpip.Error) { + s.mu.RLock() + defer s.mu.RUnlock() + + nic, ok := s.nics[tcpip.NICID(NICID)] + if !ok { + return 0, &tcpip.ErrUnknownNICID{} + } + + return nic.gro.getInterval(), nil +} + +// SetGROTimeout sets the GRO timeout. +func (s *Stack) SetGROTimeout(NICID int32, timeout time.Duration) tcpip.Error { + s.mu.RLock() + defer s.mu.RUnlock() + + nic, ok := s.nics[tcpip.NICID(NICID)] + if !ok { + return &tcpip.ErrUnknownNICID{} + } + + nic.gro.setInterval(timeout) + return nil +} + // SetRouteTable assigns the route table to be used by this stack. It // specifies which NIC to use for given destination address ranges. // @@ -788,7 +816,7 @@ func (s *Stack) NewPacketEndpoint(cooked bool, netProto tcpip.NetworkProtocolNum } // NICContext is an opaque pointer used to store client-supplied NIC metadata. -type NICContext interface{} +type NICContext any // NICOptions specifies the configuration of a NIC as it is being created. // The zero value creates an enabled, unnamed NIC. @@ -808,6 +836,9 @@ type NICOptions struct { // QDisc is the queue discipline to use for this NIC. QDisc QueueingDiscipline + + // GROTimeout specifies the GRO timeout. Zero bypasses GRO. + GROTimeout time.Duration } // CreateNICWithOptions creates a NIC with the provided id, LinkEndpoint, and @@ -920,15 +951,12 @@ func (s *Stack) RemoveNIC(id tcpip.NICID) tcpip.Error { // removeNICLocked removes NIC and all related routes from the network stack. // -// s.mu must be locked. +// +checklocks:s.mu func (s *Stack) removeNICLocked(id tcpip.NICID) tcpip.Error { nic, ok := s.nics[id] if !ok { return &tcpip.ErrUnknownNICID{} } - if nic.IsLoopback() { - return &tcpip.ErrNotSupported{} - } delete(s.nics, id) // Remove routes in-place. n tracks the number of routes written. @@ -1021,9 +1049,11 @@ func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo { } netStats := make(map[tcpip.NetworkProtocolNumber]NetworkEndpointStats) + nic.mu.RLock() for proto, netEP := range nic.networkEndpoints { netStats[proto] = netEP.Stats() } + nic.mu.RUnlock() info := NICInfo{ Name: nic.name, @@ -1150,6 +1180,9 @@ func (s *Stack) getAddressEP(nic *nic, localAddr, remoteAddr tcpip.Address, netP // // Returns nil if validation fails. func (s *Stack) NewRouteForMulticast(nicID tcpip.NICID, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route { + s.mu.RLock() + defer s.mu.RUnlock() + nic, ok := s.nics[nicID] if !ok || !nic.Enabled() { return nil @@ -1164,7 +1197,7 @@ func (s *Stack) NewRouteForMulticast(nicID tcpip.NICID, remoteAddr tcpip.Address // findLocalRouteFromNICRLocked is like findLocalRouteRLocked but finds a route // from the specified NIC. // -// Precondition: s.mu must be read locked. +// +checklocksread:s.mu func (s *Stack) findLocalRouteFromNICRLocked(localAddressNIC *nic, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route { localAddressEndpoint := localAddressNIC.getAddressOrCreateTempInner(netProto, localAddr, false /* createTemp */, NeverPrimaryEndpoint) if localAddressEndpoint == nil { @@ -1217,7 +1250,7 @@ func (s *Stack) findLocalRouteFromNICRLocked(localAddressNIC *nic, localAddr, re // A local route is a route to some remote address which the stack owns. That // is, a local route is a route where packets never have to leave the stack. // -// Precondition: s.mu must be read locked. +// +checklocksread:s.mu func (s *Stack) findLocalRouteRLocked(localAddressNICID tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route { if len(localAddr) == 0 { localAddr = remoteAddr @@ -1384,7 +1417,8 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n } } - return nil, &tcpip.ErrNoRoute{} + // TODO(https://gvisor.dev/issues/8105): This should be ErrNetworkUnreachable. + return nil, &tcpip.ErrHostUnreachable{} } if id == 0 { @@ -1404,11 +1438,13 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n } if needRoute { - return nil, &tcpip.ErrNoRoute{} + // TODO(https://gvisor.dev/issues/8105): This should be ErrNetworkUnreachable. + return nil, &tcpip.ErrHostUnreachable{} } if header.IsV6LoopbackAddress(remoteAddr) { return nil, &tcpip.ErrBadLocalAddress{} } + // TODO(https://gvisor.dev/issues/8105): This should be ErrNetworkUnreachable. return nil, &tcpip.ErrNetworkUnreachable{} } @@ -1422,7 +1458,10 @@ func (s *Stack) CheckNetworkProtocol(protocol tcpip.NetworkProtocolNumber) bool // CheckDuplicateAddress performs duplicate address detection for the address on // the specified interface. func (s *Stack) CheckDuplicateAddress(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, h DADCompletionHandler) (DADCheckAddressDisposition, tcpip.Error) { + s.mu.RLock() nic, ok := s.nics[nicID] + s.mu.RUnlock() + if !ok { return 0, &tcpip.ErrUnknownNICID{} } @@ -1727,6 +1766,12 @@ func (s *Stack) Wait() { } } +// Destroy destroys the stack with all endpoints. +func (s *Stack) Destroy() { + s.Close() + s.Wait() +} + // Pause pauses any protocol level background workers. func (s *Stack) Pause() { for _, p := range s.transportProtocols { @@ -1792,6 +1837,7 @@ func (s *Stack) UnregisterPacketEndpoint(nicID tcpip.NICID, netProto tcpip.Netwo s.unregisterPacketEndpointLocked(nicID, netProto, ep) } +// +checklocks:s.mu func (s *Stack) unregisterPacketEndpointLocked(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) { // If no NIC is specified, unregister on all devices. if nicID == 0 { @@ -2062,7 +2108,7 @@ const ( // ParsePacketBufferTransport parses the provided packet buffer's transport // header. -func (s *Stack) ParsePacketBufferTransport(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) ParseResult { +func (s *Stack) ParsePacketBufferTransport(protocol tcpip.TransportProtocolNumber, pkt PacketBufferPtr) ParseResult { pkt.TransportProtocolNumber = protocol // Parse the transport header if present. state, ok := s.transportProtocols[protocol] diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_mutex.go new file mode 100644 index 000000000..23e5d0985 --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type stackRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var stacklockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type stacklockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *stackRWMutex) Lock() { + locking.AddGLock(stackprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *stackRWMutex) NestedLock(i stacklockNameIndex) { + locking.AddGLock(stackprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *stackRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(stackprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *stackRWMutex) NestedUnlock(i stacklockNameIndex) { + m.mu.Unlock() + locking.DelGLock(stackprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *stackRWMutex) RLock() { + locking.AddGLock(stackprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *stackRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(stackprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *stackRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *stackRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *stackRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var stackprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func stackinitLockNames() {} + +func init() { + stackinitLockNames() + stackprefixIndex = locking.NewMutexClass(reflect.TypeOf(stackRWMutex{}), stacklockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_options.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_options.go index 80e8e0089..57af874a7 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_options.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_options.go @@ -50,7 +50,7 @@ type ReceiveBufferSizeOption struct { type TCPInvalidRateLimitOption time.Duration // SetOption allows setting stack wide options. -func (s *Stack) SetOption(option interface{}) tcpip.Error { +func (s *Stack) SetOption(option any) tcpip.Error { switch v := option.(type) { case tcpip.SendBufferSizeOption: // Make sure we don't allow lowering the buffer below minimum @@ -99,7 +99,7 @@ func (s *Stack) SetOption(option interface{}) tcpip.Error { } // Option allows retrieving stack wide options. -func (s *Stack) Option(option interface{}) tcpip.Error { +func (s *Stack) Option(option any) tcpip.Error { switch v := option.(type) { case *tcpip.SendBufferSizeOption: s.mu.RLock() diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_state_autogen.go index 1e191d009..f0f97be3e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/stack_state_autogen.go @@ -6,6 +6,30 @@ import ( "gvisor.dev/gvisor/pkg/state" ) +func (r *addressStateRefs) StateTypeName() string { + return "pkg/tcpip/stack.addressStateRefs" +} + +func (r *addressStateRefs) StateFields() []string { + return []string{ + "refCount", + } +} + +func (r *addressStateRefs) beforeSave() {} + +// +checklocksignore +func (r *addressStateRefs) StateSave(stateSinkObject state.Sink) { + r.beforeSave() + stateSinkObject.Save(0, &r.refCount) +} + +// +checklocksignore +func (r *addressStateRefs) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &r.refCount) + stateSourceObject.AfterLoad(r.afterLoad) +} + func (t *tuple) StateTypeName() string { return "pkg/tcpip/stack.tuple" } @@ -188,6 +212,62 @@ func (bkt *bucket) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(0, &bkt.tuples) } +func (l *groPacketList) StateTypeName() string { + return "pkg/tcpip/stack.groPacketList" +} + +func (l *groPacketList) StateFields() []string { + return []string{ + "head", + "tail", + } +} + +func (l *groPacketList) beforeSave() {} + +// +checklocksignore +func (l *groPacketList) StateSave(stateSinkObject state.Sink) { + l.beforeSave() + stateSinkObject.Save(0, &l.head) + stateSinkObject.Save(1, &l.tail) +} + +func (l *groPacketList) afterLoad() {} + +// +checklocksignore +func (l *groPacketList) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &l.head) + stateSourceObject.Load(1, &l.tail) +} + +func (e *groPacketEntry) StateTypeName() string { + return "pkg/tcpip/stack.groPacketEntry" +} + +func (e *groPacketEntry) StateFields() []string { + return []string{ + "next", + "prev", + } +} + +func (e *groPacketEntry) beforeSave() {} + +// +checklocksignore +func (e *groPacketEntry) StateSave(stateSinkObject state.Sink) { + e.beforeSave() + stateSinkObject.Save(0, &e.next) + stateSinkObject.Save(1, &e.prev) +} + +func (e *groPacketEntry) afterLoad() {} + +// +checklocksignore +func (e *groPacketEntry) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &e.next) + stateSourceObject.Load(1, &e.prev) +} + func (it *IPTables) StateTypeName() string { return "pkg/tcpip/stack.IPTables" } @@ -407,11 +487,36 @@ func (e *neighborEntryEntry) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &e.prev) } -func (pk *PacketBuffer) StateTypeName() string { - return "pkg/tcpip/stack.PacketBuffer" +func (pk *PacketBufferPtr) StateTypeName() string { + return "pkg/tcpip/stack.PacketBufferPtr" +} + +func (pk *PacketBufferPtr) StateFields() []string { + return []string{ + "packetBuffer", + } +} + +func (pk *PacketBufferPtr) beforeSave() {} + +// +checklocksignore +func (pk *PacketBufferPtr) StateSave(stateSinkObject state.Sink) { + pk.beforeSave() + stateSinkObject.Save(0, &pk.packetBuffer) +} + +func (pk *PacketBufferPtr) afterLoad() {} + +// +checklocksignore +func (pk *PacketBufferPtr) StateLoad(stateSourceObject state.Source) { + stateSourceObject.Load(0, &pk.packetBuffer) +} + +func (pk *packetBuffer) StateTypeName() string { + return "pkg/tcpip/stack.packetBuffer" } -func (pk *PacketBuffer) StateFields() []string { +func (pk *packetBuffer) StateFields() []string { return []string{ "packetBufferRefs", "buf", @@ -429,16 +534,16 @@ func (pk *PacketBuffer) StateFields() []string { "dnatDone", "PktType", "NICID", - "RXTransportChecksumValidated", + "RXChecksumValidated", "NetworkPacketInfo", "tuple", } } -func (pk *PacketBuffer) beforeSave() {} +func (pk *packetBuffer) beforeSave() {} // +checklocksignore -func (pk *PacketBuffer) StateSave(stateSinkObject state.Sink) { +func (pk *packetBuffer) StateSave(stateSinkObject state.Sink) { pk.beforeSave() stateSinkObject.Save(0, &pk.packetBufferRefs) stateSinkObject.Save(1, &pk.buf) @@ -456,15 +561,15 @@ func (pk *PacketBuffer) StateSave(stateSinkObject state.Sink) { stateSinkObject.Save(13, &pk.dnatDone) stateSinkObject.Save(14, &pk.PktType) stateSinkObject.Save(15, &pk.NICID) - stateSinkObject.Save(16, &pk.RXTransportChecksumValidated) + stateSinkObject.Save(16, &pk.RXChecksumValidated) stateSinkObject.Save(17, &pk.NetworkPacketInfo) stateSinkObject.Save(18, &pk.tuple) } -func (pk *PacketBuffer) afterLoad() {} +func (pk *packetBuffer) afterLoad() {} // +checklocksignore -func (pk *PacketBuffer) StateLoad(stateSourceObject state.Source) { +func (pk *packetBuffer) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(0, &pk.packetBufferRefs) stateSourceObject.Load(1, &pk.buf) stateSourceObject.Load(2, &pk.reserved) @@ -481,7 +586,7 @@ func (pk *PacketBuffer) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(13, &pk.dnatDone) stateSourceObject.Load(14, &pk.PktType) stateSourceObject.Load(15, &pk.NICID) - stateSourceObject.Load(16, &pk.RXTransportChecksumValidated) + stateSourceObject.Load(16, &pk.RXChecksumValidated) stateSourceObject.Load(17, &pk.NetworkPacketInfo) stateSourceObject.Load(18, &pk.tuple) } @@ -1462,18 +1567,22 @@ func (e *tupleEntry) StateLoad(stateSourceObject state.Source) { } func init() { + state.Register((*addressStateRefs)(nil)) state.Register((*tuple)(nil)) state.Register((*tupleID)(nil)) state.Register((*conn)(nil)) state.Register((*ConnTrack)(nil)) state.Register((*bucket)(nil)) + state.Register((*groPacketList)(nil)) + state.Register((*groPacketEntry)(nil)) state.Register((*IPTables)(nil)) state.Register((*Table)(nil)) state.Register((*Rule)(nil)) state.Register((*IPHeaderFilter)(nil)) state.Register((*neighborEntryList)(nil)) state.Register((*neighborEntryEntry)(nil)) - state.Register((*PacketBuffer)(nil)) + state.Register((*PacketBufferPtr)(nil)) + state.Register((*packetBuffer)(nil)) state.Register((*headerInfo)(nil)) state.Register((*PacketData)(nil)) state.Register((*PacketBufferList)(nil)) diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/state_conn_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/state_conn_mutex.go new file mode 100644 index 000000000..f1593040e --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/state_conn_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type stateConnRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var stateConnlockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type stateConnlockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *stateConnRWMutex) Lock() { + locking.AddGLock(stateConnprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *stateConnRWMutex) NestedLock(i stateConnlockNameIndex) { + locking.AddGLock(stateConnprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *stateConnRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(stateConnprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *stateConnRWMutex) NestedUnlock(i stateConnlockNameIndex) { + m.mu.Unlock() + locking.DelGLock(stateConnprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *stateConnRWMutex) RLock() { + locking.AddGLock(stateConnprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *stateConnRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(stateConnprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *stateConnRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *stateConnRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *stateConnRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var stateConnprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func stateConninitLockNames() {} + +func init() { + stateConninitLockNames() + stateConnprefixIndex = locking.NewMutexClass(reflect.TypeOf(stateConnRWMutex{}), stateConnlockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_demuxer.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_demuxer.go index 8996c25eb..adb54ffe4 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_demuxer.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_demuxer.go @@ -17,7 +17,6 @@ package stack import ( "fmt" - "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/hash/jenkins" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -32,7 +31,7 @@ type protocolIDs struct { // transportEndpoints manages all endpoints of a given protocol. It has its own // mutex so as to reduce interference between protocols. type transportEndpoints struct { - mu sync.RWMutex + mu transportEndpointsRWMutex // +checklocks:mu endpoints map[TransportEndpointID]*endpointsByNIC // rawEndpoints contains endpoints for raw sockets, which receive all @@ -138,7 +137,7 @@ type endpointsByNIC struct { // seed is a random secret for a jenkins hash. seed uint32 - mu sync.RWMutex + mu endpointsByNICRWMutex // +checklocks:mu endpoints map[tcpip.NICID]*multiPortEndpoint } @@ -156,7 +155,7 @@ func (epsByNIC *endpointsByNIC) transportEndpoints() []TransportEndpoint { // handlePacket is called by the stack when new packets arrive to this transport // endpoint. It returns false if the packet could not be matched to any // transport endpoint, true otherwise. -func (epsByNIC *endpointsByNIC) handlePacket(id TransportEndpointID, pkt *PacketBuffer) bool { +func (epsByNIC *endpointsByNIC) handlePacket(id TransportEndpointID, pkt PacketBufferPtr) bool { epsByNIC.mu.RLock() mpep, ok := epsByNIC.endpoints[pkt.NICID] @@ -188,7 +187,7 @@ func (epsByNIC *endpointsByNIC) handlePacket(id TransportEndpointID, pkt *Packet } // handleError delivers an error to the transport endpoint identified by id. -func (epsByNIC *endpointsByNIC) handleError(n *nic, id TransportEndpointID, transErr TransportError, pkt *PacketBuffer) { +func (epsByNIC *endpointsByNIC) handleError(n *nic, id TransportEndpointID, transErr TransportError, pkt PacketBufferPtr) { epsByNIC.mu.RLock() mpep, ok := epsByNIC.endpoints[n.ID()] @@ -279,7 +278,7 @@ type transportDemuxer struct { // the dispatcher to delivery packets to the QueuePacket method instead of // calling HandlePacket directly on the endpoint. type queuedTransportProtocol interface { - QueuePacket(ep TransportEndpoint, id TransportEndpointID, pkt *PacketBuffer) + QueuePacket(ep TransportEndpoint, id TransportEndpointID, pkt PacketBufferPtr) } func newTransportDemuxer(stack *Stack) *transportDemuxer { @@ -346,7 +345,7 @@ type multiPortEndpoint struct { flags ports.FlagCounter - mu sync.RWMutex `state:"nosave"` + mu multiPortEndpointRWMutex `state:"nosave"` // endpoints stores the transport endpoints in the order in which they // were bound. This is required for UDP SO_REUSEADDR. // @@ -401,7 +400,7 @@ func (ep *multiPortEndpoint) selectEndpoint(id TransportEndpointID, seed uint32) return ep.endpoints[idx] } -func (ep *multiPortEndpoint) handlePacketAll(id TransportEndpointID, pkt *PacketBuffer) { +func (ep *multiPortEndpoint) handlePacketAll(id TransportEndpointID, pkt PacketBufferPtr) { ep.mu.RLock() queuedProtocol, mustQueue := ep.demux.queuedProtocols[protocolIDs{ep.netProto, ep.transProto}] // HandlePacket may modify pkt, so each endpoint needs @@ -547,7 +546,7 @@ func (d *transportDemuxer) unregisterEndpoint(netProtos []tcpip.NetworkProtocolN // deliverPacket attempts to find one or more matching transport endpoints, and // then, if matches are found, delivers the packet to them. Returns true if // the packet no longer needs to be handled. -func (d *transportDemuxer) deliverPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer, id TransportEndpointID) bool { +func (d *transportDemuxer) deliverPacket(protocol tcpip.TransportProtocolNumber, pkt PacketBufferPtr, id TransportEndpointID) bool { eps, ok := d.protocol[protocolIDs{pkt.NetworkProtocolNumber, protocol}] if !ok { return false @@ -600,7 +599,7 @@ func (d *transportDemuxer) deliverPacket(protocol tcpip.TransportProtocolNumber, // deliverRawPacket attempts to deliver the given packet and returns whether it // was delivered successfully. -func (d *transportDemuxer) deliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) bool { +func (d *transportDemuxer) deliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt PacketBufferPtr) bool { eps, ok := d.protocol[protocolIDs{pkt.NetworkProtocolNumber, protocol}] if !ok { return false @@ -634,7 +633,7 @@ func (d *transportDemuxer) deliverRawPacket(protocol tcpip.TransportProtocolNumb // endpoint. // // Returns true if the error was delivered. -func (d *transportDemuxer) deliverError(n *nic, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt *PacketBuffer, id TransportEndpointID) bool { +func (d *transportDemuxer) deliverError(n *nic, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt PacketBufferPtr, id TransportEndpointID) bool { eps, ok := d.protocol[protocolIDs{net, trans}] if !ok { return false @@ -719,7 +718,7 @@ func (d *transportDemuxer) unregisterRawEndpoint(netProto tcpip.NetworkProtocolN eps.mu.Unlock() } -func isInboundMulticastOrBroadcast(pkt *PacketBuffer, localAddr tcpip.Address) bool { +func isInboundMulticastOrBroadcast(pkt PacketBufferPtr, localAddr tcpip.Address) bool { return pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(localAddr) || header.IsV6MulticastAddress(localAddr) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_endpoints_mutex.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_endpoints_mutex.go new file mode 100644 index 000000000..2098d77ee --- /dev/null +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/transport_endpoints_mutex.go @@ -0,0 +1,96 @@ +package stack + +import ( + "reflect" + + "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/sync/locking" +) + +// RWMutex is sync.RWMutex with the correctness validator. +type transportEndpointsRWMutex struct { + mu sync.RWMutex +} + +// lockNames is a list of user-friendly lock names. +// Populated in init. +var transportEndpointslockNames []string + +// lockNameIndex is used as an index passed to NestedLock and NestedUnlock, +// refering to an index within lockNames. +// Values are specified using the "consts" field of go_template_instance. +type transportEndpointslockNameIndex int + +// DO NOT REMOVE: The following function automatically replaced with lock index constants. +// LOCK_NAME_INDEX_CONSTANTS +const () + +// Lock locks m. +// +checklocksignore +func (m *transportEndpointsRWMutex) Lock() { + locking.AddGLock(transportEndpointsprefixIndex, -1) + m.mu.Lock() +} + +// NestedLock locks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *transportEndpointsRWMutex) NestedLock(i transportEndpointslockNameIndex) { + locking.AddGLock(transportEndpointsprefixIndex, int(i)) + m.mu.Lock() +} + +// Unlock unlocks m. +// +checklocksignore +func (m *transportEndpointsRWMutex) Unlock() { + m.mu.Unlock() + locking.DelGLock(transportEndpointsprefixIndex, -1) +} + +// NestedUnlock unlocks m knowing that another lock of the same type is held. +// +checklocksignore +func (m *transportEndpointsRWMutex) NestedUnlock(i transportEndpointslockNameIndex) { + m.mu.Unlock() + locking.DelGLock(transportEndpointsprefixIndex, int(i)) +} + +// RLock locks m for reading. +// +checklocksignore +func (m *transportEndpointsRWMutex) RLock() { + locking.AddGLock(transportEndpointsprefixIndex, -1) + m.mu.RLock() +} + +// RUnlock undoes a single RLock call. +// +checklocksignore +func (m *transportEndpointsRWMutex) RUnlock() { + m.mu.RUnlock() + locking.DelGLock(transportEndpointsprefixIndex, -1) +} + +// RLockBypass locks m for reading without executing the validator. +// +checklocksignore +func (m *transportEndpointsRWMutex) RLockBypass() { + m.mu.RLock() +} + +// RUnlockBypass undoes a single RLockBypass call. +// +checklocksignore +func (m *transportEndpointsRWMutex) RUnlockBypass() { + m.mu.RUnlock() +} + +// DowngradeLock atomically unlocks rw for writing and locks it for reading. +// +checklocksignore +func (m *transportEndpointsRWMutex) DowngradeLock() { + m.mu.DowngradeLock() +} + +var transportEndpointsprefixIndex *locking.MutexClass + +// DO NOT REMOVE: The following function is automatically replaced. +func transportEndpointsinitLockNames() {} + +func init() { + transportEndpointsinitLockNames() + transportEndpointsprefixIndex = locking.NewMutexClass(reflect.TypeOf(transportEndpointsRWMutex{}), transportEndpointslockNames) +} diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go index cd981ba60..a43970901 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go @@ -2036,6 +2036,16 @@ type NICNeighborStats struct { // entry in Unreachable state. UnreachableEntryLookups *StatCounter + // DroppedConfirmationForNoninitiatedNeighbor counts the number of neighbor + // responses that were dropped because they didn't match an entry in the + // cache. + DroppedConfirmationForNoninitiatedNeighbor *StatCounter + + // DroppedInvalidLinkAddressConfirmations counts the number of neighbor + // responses that were ignored because they had an invalid source link-layer + // address. + DroppedInvalidLinkAddressConfirmations *StatCounter + // LINT.ThenChange(stack/nic_stats.go:multiCounterNICNeighborStats) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip_state_autogen.go index faeff62da..4965e3a18 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip_state_autogen.go @@ -552,25 +552,25 @@ func (e *ErrNoPortAvailable) afterLoad() {} func (e *ErrNoPortAvailable) StateLoad(stateSourceObject state.Source) { } -func (e *ErrNoRoute) StateTypeName() string { - return "pkg/tcpip.ErrNoRoute" +func (e *ErrHostUnreachable) StateTypeName() string { + return "pkg/tcpip.ErrHostUnreachable" } -func (e *ErrNoRoute) StateFields() []string { +func (e *ErrHostUnreachable) StateFields() []string { return []string{} } -func (e *ErrNoRoute) beforeSave() {} +func (e *ErrHostUnreachable) beforeSave() {} // +checklocksignore -func (e *ErrNoRoute) StateSave(stateSinkObject state.Sink) { +func (e *ErrHostUnreachable) StateSave(stateSinkObject state.Sink) { e.beforeSave() } -func (e *ErrNoRoute) afterLoad() {} +func (e *ErrHostUnreachable) afterLoad() {} // +checklocksignore -func (e *ErrNoRoute) StateLoad(stateSourceObject state.Source) { +func (e *ErrHostUnreachable) StateLoad(stateSourceObject state.Source) { } func (e *ErrNoSuchFile) StateTypeName() string { @@ -1295,7 +1295,7 @@ func (c *ReceivableControlMessages) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(16, &c.HasOriginalDstAddress) stateSourceObject.Load(17, &c.OriginalDstAddress) stateSourceObject.Load(18, &c.SockErr) - stateSourceObject.LoadValue(0, new(int64), func(y interface{}) { c.loadTimestamp(y.(int64)) }) + stateSourceObject.LoadValue(0, new(int64), func(y any) { c.loadTimestamp(y.(int64)) }) } func (l *LinkPacketInfo) StateTypeName() string { @@ -1654,7 +1654,7 @@ func init() { state.Register((*ErrNetworkUnreachable)(nil)) state.Register((*ErrNoBufferSpace)(nil)) state.Register((*ErrNoPortAvailable)(nil)) - state.Register((*ErrNoRoute)(nil)) + state.Register((*ErrHostUnreachable)(nil)) state.Register((*ErrNoSuchFile)(nil)) state.Register((*ErrNotConnected)(nil)) state.Register((*ErrNotPermitted)(nil)) diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/endpoint.go index 4d26400f8..8c737d51f 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/endpoint.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/ports" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -35,7 +36,7 @@ type icmpPacket struct { icmpPacketEntry senderAddress tcpip.FullAddress packetInfo tcpip.IPPacketInfo - data *stack.PacketBuffer + data stack.PacketBufferPtr receivedAt time.Time `state:".(int64)"` // tosOrTClass stores either the Type of Service for IPv4 or the Traffic Class @@ -299,7 +300,7 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp e.stats.WriteErrors.WriteClosed.Increment() case *tcpip.ErrInvalidEndpointState: e.stats.WriteErrors.InvalidEndpointState.Increment() - case *tcpip.ErrNoRoute, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: + case *tcpip.ErrHostUnreachable, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: // Errors indicating any problem with IP routing of the packet. e.stats.SendErrors.NoRoute.Increment() default: @@ -336,6 +337,11 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp } defer ctx.Release() + // Prevents giant buffer allocations. + if p.Len() > header.DatagramMaximumSize { + return 0, &tcpip.ErrMessageTooLong{} + } + v := bufferv2.NewView(p.Len()) defer v.Release() if _, err := io.CopyN(v, p, int64(p.Len())); err != nil { @@ -406,7 +412,7 @@ func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *buffer } pkt := ctx.TryNewPacketBuffer(header.ICMPv4MinimumSize+int(maxHeaderLength), bufferv2.Buffer{}) - if pkt == nil { + if pkt.IsNil() { return &tcpip.ErrWouldBlock{} } defer pkt.DecRef() @@ -425,7 +431,7 @@ func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *buffer } icmpv4.SetChecksum(0) - icmpv4.SetChecksum(^header.Checksum(icmpv4, header.Checksum(data.AsSlice(), 0))) + icmpv4.SetChecksum(^checksum.Checksum(icmpv4, checksum.Checksum(data.AsSlice(), 0))) pkt.Data().AppendView(data.Clone()) // Because this icmp endpoint is implemented in the transport layer, we can @@ -448,7 +454,7 @@ func send6(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *buffer } pkt := ctx.TryNewPacketBuffer(header.ICMPv6MinimumSize+int(maxHeaderLength), bufferv2.Buffer{}) - if pkt == nil { + if pkt.IsNil() { return &tcpip.ErrWouldBlock{} } defer pkt.DecRef() @@ -465,13 +471,13 @@ func send6(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *buffer } pkt.Data().AppendView(data.Clone()) - dataRange := pkt.Data().AsRange() + pktData := pkt.Data() icmpv6.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: icmpv6, Src: src, Dst: dst, - PayloadCsum: dataRange.Checksum(), - PayloadLen: dataRange.Size(), + PayloadCsum: pktData.Checksum(), + PayloadLen: pktData.Size(), })) // Because this icmp endpoint is implemented in the transport layer, we can @@ -690,7 +696,7 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask { // HandlePacket is called by the stack when new packets arrive to this transport // endpoint. -func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) { +func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) { // Only accept echo replies. switch e.net.NetProto() { case header.IPv4ProtocolNumber: @@ -778,7 +784,7 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB } // HandleError implements stack.TransportEndpoint. -func (*endpoint) HandleError(stack.TransportError, *stack.PacketBuffer) {} +func (*endpoint) HandleError(stack.TransportError, stack.PacketBufferPtr) {} // State implements tcpip.Endpoint.State. The ICMP endpoint currently doesn't // expose internal socket state. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/icmp_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/icmp_state_autogen.go index 5b7cce257..4ebbd871f 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/icmp_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/icmp_state_autogen.go @@ -48,7 +48,7 @@ func (p *icmpPacket) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(3, &p.data) stateSourceObject.Load(5, &p.tosOrTClass) stateSourceObject.Load(6, &p.ttlOrHopLimit) - stateSourceObject.LoadValue(4, new(int64), func(y interface{}) { p.loadReceivedAt(y.(int64)) }) + stateSourceObject.LoadValue(4, new(int64), func(y any) { p.loadReceivedAt(y.(int64)) }) } func (e *endpoint) StateTypeName() string { diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/protocol.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/protocol.go index 7e6e3db18..d9833e478 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/protocol.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/icmp/protocol.go @@ -100,7 +100,7 @@ func (p *protocol) ParsePorts(v []byte) (src, dst uint16, err tcpip.Error) { // HandleUnknownDestinationPacket handles packets targeted at this protocol but // that don't match any existing endpoint. -func (*protocol) HandleUnknownDestinationPacket(stack.TransportEndpointID, *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition { +func (*protocol) HandleUnknownDestinationPacket(stack.TransportEndpointID, stack.PacketBufferPtr) stack.UnknownDestinationPacketDisposition { return stack.UnknownDestinationPacketHandled } @@ -127,7 +127,7 @@ func (*protocol) Pause() {} func (*protocol) Resume() {} // Parse implements stack.TransportProtocol.Parse. -func (*protocol) Parse(pkt *stack.PacketBuffer) bool { +func (*protocol) Parse(pkt stack.PacketBufferPtr) bool { // Right now, the Parse() method is tied to enabled protocols passed into // stack.New. This works for UDP and TCP, but we handle ICMP traffic even // when netstack users don't pass ICMP as a supported protocol. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/network/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/network/endpoint.go index c5a5b8f91..fa062ea9d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/network/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/network/endpoint.go @@ -118,10 +118,9 @@ type multicastMembership struct { // Init initializes the endpoint. func (e *Endpoint) Init(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ops *tcpip.SocketOptions, waiterQueue *waiter.Queue) { e.mu.Lock() - memberships := e.multicastMemberships - e.mu.Unlock() - if memberships != nil { - panic(fmt.Sprintf("endpoint is already initialized; got e.multicastMemberships = %#v, want = nil", memberships)) + defer e.mu.Unlock() + if e.multicastMemberships != nil { + panic(fmt.Sprintf("endpoint is already initialized; got e.multicastMemberships = %#v, want = nil", e.multicastMemberships)) } switch netProto { @@ -130,27 +129,24 @@ func (e *Endpoint) Init(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, tr panic(fmt.Sprintf("invalid protocol number = %d", netProto)) } - *e = Endpoint{ - stack: s, - ops: ops, - netProto: netProto, - transProto: transProto, - waiterQueue: waiterQueue, - - info: stack.TransportEndpointInfo{ - NetProto: netProto, - TransProto: transProto, - }, - effectiveNetProto: netProto, - ipv4TTL: tcpip.UseDefaultIPv4TTL, - ipv6HopLimit: tcpip.UseDefaultIPv6HopLimit, - // Linux defaults to TTL=1. - multicastTTL: 1, - multicastMemberships: make(map[multicastMembership]struct{}), + e.stack = s + e.ops = ops + e.netProto = netProto + e.transProto = transProto + e.waiterQueue = waiterQueue + e.infoMu.Lock() + e.info = stack.TransportEndpointInfo{ + NetProto: netProto, + TransProto: transProto, } + e.infoMu.Unlock() + e.effectiveNetProto = netProto + e.ipv4TTL = tcpip.UseDefaultIPv4TTL + e.ipv6HopLimit = tcpip.UseDefaultIPv6HopLimit - e.mu.Lock() - defer e.mu.Unlock() + // Linux defaults to TTL=1. + e.multicastTTL = 1 + e.multicastMemberships = make(map[multicastMembership]struct{}) e.setEndpointState(transport.DatagramEndpointStateInitial) } @@ -269,14 +265,14 @@ func (c *WriteContext) PacketInfo() WritePacketInfo { // // If this method returns nil, the caller should wait for the endpoint to become // writable. -func (c *WriteContext) TryNewPacketBuffer(reserveHdrBytes int, data bufferv2.Buffer) *stack.PacketBuffer { +func (c *WriteContext) TryNewPacketBuffer(reserveHdrBytes int, data bufferv2.Buffer) stack.PacketBufferPtr { e := c.e e.sendBufferSizeInUseMu.Lock() defer e.sendBufferSizeInUseMu.Unlock() if !e.hasSendSpaceRLocked() { - return nil + return stack.PacketBufferPtr{} } // Note that we allow oversubscription - if there is any space at all in the @@ -312,7 +308,7 @@ func (c *WriteContext) TryNewPacketBuffer(reserveHdrBytes int, data bufferv2.Buf } // WritePacket attempts to write the packet. -func (c *WriteContext) WritePacket(pkt *stack.PacketBuffer, headerIncluded bool) tcpip.Error { +func (c *WriteContext) WritePacket(pkt stack.PacketBufferPtr, headerIncluded bool) tcpip.Error { c.e.mu.RLock() pkt.Owner = c.e.owner c.e.mu.RUnlock() @@ -447,7 +443,7 @@ func (e *Endpoint) AcquireContextForWrite(opts tcpip.WriteOptions) (WriteContext // interface (usually when using link-local addresses), make sure the // interface matches the specified local interface. if nicID != 0 && nicID != pktInfoNICID { - return WriteContext{}, &tcpip.ErrNoRoute{} + return WriteContext{}, &tcpip.ErrHostUnreachable{} } // If a local address is not specified, then we need to make sure the @@ -459,7 +455,7 @@ func (e *Endpoint) AcquireContextForWrite(opts tcpip.WriteOptions) (WriteContext // // The bound interface is usually only set for link-local addresses. if info.BindNICID != 0 && info.BindNICID != pktInfoNICID { - return WriteContext{}, &tcpip.ErrNoRoute{} + return WriteContext{}, &tcpip.ErrHostUnreachable{} } if len(info.ID.LocalAddress) != 0 && e.stack.CheckLocalAddress(pktInfoNICID, header.IPv6ProtocolNumber, info.ID.LocalAddress) == 0 { return WriteContext{}, &tcpip.ErrBadLocalAddress{} @@ -483,7 +479,7 @@ func (e *Endpoint) AcquireContextForWrite(opts tcpip.WriteOptions) (WriteContext } else { if info.BindNICID != 0 { if nicID != 0 && nicID != info.BindNICID { - return WriteContext{}, &tcpip.ErrNoRoute{} + return WriteContext{}, &tcpip.ErrHostUnreachable{} } nicID = info.BindNICID @@ -652,6 +648,7 @@ func (e *Endpoint) ConnectAndThen(addr tcpip.FullAddress, f func(netProto tcpip. } if err := f(r.NetProto(), info.ID, id); err != nil { + r.Release() return err } @@ -951,7 +948,7 @@ func (e *Endpoint) SetSockOpt(opt tcpip.SettableSocketOption) tcpip.Error { e.multicastMemberships[memToInsert] = struct{}{} case *tcpip.RemoveMembershipOption: - if !header.IsV4MulticastAddress(v.MulticastAddr) && !header.IsV6MulticastAddress(v.MulticastAddr) { + if !(header.IsV4MulticastAddress(v.MulticastAddr) && e.netProto == header.IPv4ProtocolNumber) && !(header.IsV6MulticastAddress(v.MulticastAddr) && e.netProto == header.IPv6ProtocolNumber) { return &tcpip.ErrInvalidOptionValue{} } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/noop/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/noop/endpoint.go index be2adae1c..3e9c4c4bb 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/noop/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/internal/noop/endpoint.go @@ -137,7 +137,7 @@ func (*endpoint) GetSockOptInt(tcpip.SockOptInt) (int, tcpip.Error) { } // HandlePacket implements stack.RawTransportEndpoint.HandlePacket. -func (*endpoint) HandlePacket(pkt *stack.PacketBuffer) { +func (*endpoint) HandlePacket(pkt stack.PacketBufferPtr) { panic(fmt.Sprintf("unreachable: noop.endpoint should never be registered, but got packet: %+v", pkt)) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/endpoint.go index f82e36517..a39af2dbb 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/endpoint.go @@ -40,7 +40,7 @@ import ( type packet struct { packetEntry // data holds the actual packet data, including any headers and payload. - data *stack.PacketBuffer + data stack.PacketBufferPtr receivedAt time.Time `state:".(int64)"` // senderAddr is the network address of the sender. senderAddr tcpip.FullAddress @@ -234,6 +234,11 @@ func (ep *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tc return 0, &tcpip.ErrInvalidOptionValue{} } + // Prevents giant buffer allocations. + if p.Len() > header.DatagramMaximumSize { + return 0, &tcpip.ErrMessageTooLong{} + } + var payload bufferv2.Buffer if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil { return 0, &tcpip.ErrBadBuffer{} @@ -412,7 +417,7 @@ func (ep *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) { } // HandlePacket implements stack.PacketEndpoint.HandlePacket. -func (ep *endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { +func (ep *endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) { ep.rcvMu.Lock() // Drop the packet if our buffer is currently full. diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/packet_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/packet_state_autogen.go index 433feb830..5e344c8d9 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/packet_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/packet/packet_state_autogen.go @@ -42,7 +42,7 @@ func (p *packet) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &p.data) stateSourceObject.Load(3, &p.senderAddr) stateSourceObject.Load(4, &p.packetInfo) - stateSourceObject.LoadValue(2, new(int64), func(y interface{}) { p.loadReceivedAt(y.(int64)) }) + stateSourceObject.LoadValue(2, new(int64), func(y any) { p.loadReceivedAt(y.(int64)) }) } func (ep *endpoint) StateTypeName() string { diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/endpoint.go index 4580dd79b..dabe6587a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/endpoint.go @@ -33,6 +33,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/transport" @@ -45,7 +46,7 @@ type rawPacket struct { rawPacketEntry // data holds the actual packet data, including any headers and // payload. - data *stack.PacketBuffer + data stack.PacketBufferPtr receivedAt time.Time `state:".(int64)"` // senderAddr is the network address of the sender. senderAddr tcpip.FullAddress @@ -326,7 +327,7 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp e.stats.WriteErrors.WriteClosed.Increment() case *tcpip.ErrInvalidEndpointState: e.stats.WriteErrors.InvalidEndpointState.Increment() - case *tcpip.ErrNoRoute, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: + case *tcpip.ErrHostUnreachable, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: // Errors indicating any problem with IP routing of the packet. e.stats.SendErrors.NoRoute.Increment() default: @@ -344,11 +345,17 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp if err != nil { return 0, err } + defer ctx.Release() if p.Len() > int(ctx.MTU()) { return 0, &tcpip.ErrMessageTooLong{} } + // Prevents giant buffer allocations. + if p.Len() > header.DatagramMaximumSize { + return 0, &tcpip.ErrMessageTooLong{} + } + var payload bufferv2.Buffer defer payload.Release() if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil { @@ -358,19 +365,19 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp if packetInfo := ctx.PacketInfo(); packetInfo.NetProto == header.IPv6ProtocolNumber && ipv6ChecksumOffset >= 0 { // Make sure we can fit the checksum. - if payload.Size() < int64(ipv6ChecksumOffset+header.ChecksumSize) { + if payload.Size() < int64(ipv6ChecksumOffset+checksum.Size) { return 0, &tcpip.ErrInvalidOptionValue{} } payloadView, _ := payload.PullUp(ipv6ChecksumOffset, int(payload.Size())-ipv6ChecksumOffset) xsum := header.PseudoHeaderChecksum(e.transProto, packetInfo.LocalAddress, packetInfo.RemoteAddress, uint16(payload.Size())) - header.PutChecksum(payloadView.AsSlice(), 0) - xsum = header.ChecksumBuffer(payload, xsum) - header.PutChecksum(payloadView.AsSlice(), ^xsum) + checksum.Put(payloadView.AsSlice(), 0) + xsum = checksum.Combine(payload.Checksum(0), xsum) + checksum.Put(payloadView.AsSlice(), ^xsum) } pkt := ctx.TryNewPacketBuffer(int(ctx.PacketInfo().MaxHeaderLength), payload.Clone()) - if pkt == nil { + if pkt.IsNil() { return 0, &tcpip.ErrWouldBlock{} } defer pkt.DecRef() @@ -516,7 +523,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) tcpip.Error { } // Make sure the offset is aligned properly if checksum is requested. - if v > 0 && v%header.ChecksumSize != 0 { + if v > 0 && v%checksum.Size != 0 { return &tcpip.ErrInvalidOptionValue{} } @@ -579,7 +586,7 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) { } // HandlePacket implements stack.RawTransportEndpoint.HandlePacket. -func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { +func (e *endpoint) HandlePacket(pkt stack.PacketBufferPtr) { notifyReadableEvents := func() bool { e.mu.RLock() defer e.mu.RUnlock() @@ -701,13 +708,13 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { if checksumOffset := e.ipv6ChecksumOffset; checksumOffset >= 0 { bufSize := int(combinedBuf.Size()) - if bufSize < checksumOffset+header.ChecksumSize { + if bufSize < checksumOffset+checksum.Size { // Message too small to fit checksum. return false } xsum := header.PseudoHeaderChecksum(e.transProto, srcAddr, dstAddr, uint16(bufSize)) - xsum = header.ChecksumBuffer(combinedBuf, xsum) + xsum = checksum.Combine(combinedBuf.Checksum(0), xsum) if xsum != 0xFFFF { // Invalid checksum. return false diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/raw_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/raw_state_autogen.go index e00c16d21..1c9bbdbba 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/raw_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/raw/raw_state_autogen.go @@ -48,7 +48,7 @@ func (p *rawPacket) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(4, &p.packetInfo) stateSourceObject.Load(5, &p.tosOrTClass) stateSourceObject.Load(6, &p.ttlOrHopLimit) - stateSourceObject.LoadValue(2, new(int64), func(y interface{}) { p.loadReceivedAt(y.(int64)) }) + stateSourceObject.LoadValue(2, new(int64), func(y any) { p.loadReceivedAt(y.(int64)) }) } func (e *endpoint) StateTypeName() string { diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/connect.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/connect.go index 35fc9da17..451f2cef1 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/connect.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/connect.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/hash/jenkins" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/seqnum" @@ -710,7 +711,7 @@ func parseSynSegmentOptions(s *segment) header.TCPSynOptions { } var optionPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &[maxOptionSize]byte{} }, } @@ -804,7 +805,7 @@ func (e *endpoint) sendSynTCP(r *stack.Route, tf tcpFields, opts header.TCPSynOp } // This method takes ownership of pkt. -func (e *endpoint) sendTCP(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso stack.GSO) tcpip.Error { +func (e *endpoint) sendTCP(r *stack.Route, tf tcpFields, pkt stack.PacketBufferPtr, gso stack.GSO) tcpip.Error { tf.txHash = e.txHash if err := sendTCP(r, tf, pkt, gso, e.owner); err != nil { e.stats.SendErrors.SegmentSendToNetworkFailed.Increment() @@ -814,7 +815,7 @@ func (e *endpoint) sendTCP(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer return nil } -func buildTCPHdr(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso stack.GSO) { +func buildTCPHdr(r *stack.Route, tf tcpFields, pkt stack.PacketBufferPtr, gso stack.GSO) { optLen := len(tf.opts) tcp := header.TCP(pkt.TransportHeader().Push(header.TCPMinimumSize + optLen)) pkt.TransportProtocolNumber = header.TCPProtocolNumber @@ -838,12 +839,12 @@ func buildTCPHdr(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso stac // header and data and get the right sum of the TCP packet. tcp.SetChecksum(xsum) } else if r.RequiresTXTransportChecksum() { - xsum = header.ChecksumCombine(xsum, pkt.Data().AsRange().Checksum()) + xsum = checksum.Combine(xsum, pkt.Data().Checksum()) tcp.SetChecksum(^tcp.CalculateChecksum(xsum)) } } -func sendTCPBatch(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso stack.GSO, owner tcpip.PacketOwner) tcpip.Error { +func sendTCPBatch(r *stack.Route, tf tcpFields, pkt stack.PacketBufferPtr, gso stack.GSO, owner tcpip.PacketOwner) tcpip.Error { optLen := len(tf.opts) if tf.rcvWnd > math.MaxUint16 { tf.rcvWnd = math.MaxUint16 @@ -894,7 +895,7 @@ func sendTCPBatch(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso sta // sendTCP sends a TCP segment with the provided options via the provided // network endpoint and under the provided identity. This method takes // ownership of pkt. -func sendTCP(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso stack.GSO, owner tcpip.PacketOwner) tcpip.Error { +func sendTCP(r *stack.Route, tf tcpFields, pkt stack.PacketBufferPtr, gso stack.GSO, owner tcpip.PacketOwner) tcpip.Error { if tf.rcvWnd > math.MaxUint16 { tf.rcvWnd = math.MaxUint16 } @@ -967,7 +968,7 @@ func (e *endpoint) sendEmptyRaw(flags header.TCPFlags, seq, ack seqnum.Value, rc // sendRaw sends a TCP segment to the endpoint's peer. This method takes // ownership of pkt. pkt must not have any headers set. -func (e *endpoint) sendRaw(pkt *stack.PacketBuffer, flags header.TCPFlags, seq, ack seqnum.Value, rcvWnd seqnum.Size) tcpip.Error { +func (e *endpoint) sendRaw(pkt stack.PacketBufferPtr, flags header.TCPFlags, seq, ack seqnum.Value, rcvWnd seqnum.Size) tcpip.Error { var sackBlocks []header.SACKBlock if e.EndpointState() == StateEstablished && e.rcv.pendingRcvdSegments.Len() > 0 && (flags&header.TCPFlagAck != 0) { sackBlocks = e.sack.Blocks[:e.sack.NumBlocks] diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/dispatcher.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/dispatcher.go index 8b604cbf1..1c7a3c44e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/dispatcher.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/dispatcher.go @@ -326,9 +326,10 @@ func (p *processor) start(wg *sync.WaitGroup) { default: panic(fmt.Sprintf("unexpected tcp state in processor: %v", state)) } - // If there are more segments to process then + // If there are more segments to process and the + // endpoint lock is not held by user then // requeue this endpoint for processing. - if !ep.segmentQueue.empty() { + if !ep.segmentQueue.empty() && !ep.isOwnedByUser() { p.epQ.enqueue(ep) } } @@ -408,7 +409,7 @@ func (d *dispatcher) wait() { // queuePacket queues an incoming packet to the matching tcp endpoint and // also queues the endpoint to a processor queue for processing. -func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) { +func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.TransportEndpointID, clock tcpip.Clock, pkt stack.PacketBufferPtr) { d.mu.Lock() closed := d.closed d.mu.Unlock() @@ -443,7 +444,12 @@ func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.Trans return } - d.selectProcessor(id).queueEndpoint(ep) + // Only wakeup the processor if endpoint lock is not held by a user + // goroutine as endpoint.UnlockUser will wake up the processor if the + // segment queue is not empty. + if !ep.isOwnedByUser() { + d.selectProcessor(id).queueEndpoint(ep) + } } // selectProcessor uses a hash of the transport endpoint ID to queue the diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/endpoint.go index e0ffc7b95..613c6c43e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/endpoint.go @@ -605,6 +605,12 @@ func calculateAdvertisedMSS(userMSS uint16, r *stack.Route) uint16 { return maxMSS } +// isOwnedByUser() returns true if the endpoint lock is currently +// held by a user(syscall) goroutine. +func (e *endpoint) isOwnedByUser() bool { + return e.ownedByUser.Load() == 1 +} + // LockUser tries to lock e.mu and if it fails it will check if the lock is held // by another syscall goroutine. If yes, then it will goto sleep waiting for the // lock to be released, if not then it will spin till it acquires the lock or @@ -613,10 +619,31 @@ func calculateAdvertisedMSS(userMSS uint16, r *stack.Route) uint16 { // // The assumption behind spinning here being that background packet processing // should not be holding the lock for long and spinning reduces latency as we -// avoid an expensive sleep/wakeup of of the syscall goroutine). +// avoid an expensive sleep/wakeup of the syscall goroutine). // +checklocksacquire:e.mu func (e *endpoint) LockUser() { - for { + const iterations = 5 + for i := 0; i < iterations; i++ { + // Try first if the sock is locked then check if it's owned + // by another user goroutine if not then we spin, otherwise + // we just go to sleep on the Lock() and wait. + if !e.TryLock() { + // If socket is owned by the user then just go to sleep + // as the lock could be held for a reasonably long time. + if e.ownedByUser.Load() == 1 { + e.mu.Lock() + e.ownedByUser.Store(1) + return + } + // Spin but don't yield the processor since the lower half + // should yield the lock soon. + continue + } + e.ownedByUser.Store(1) + return + } + + for i := 0; i < iterations; i++ { // Try first if the sock is locked then check if it's owned // by another user goroutine if not then we spin, otherwise // we just go to sleep on the Lock() and wait. @@ -636,6 +663,10 @@ func (e *endpoint) LockUser() { e.ownedByUser.Store(1) return } + + // Finally just give up and wait for the Lock. + e.mu.Lock() + e.ownedByUser.Store(1) } // UnlockUser will check if there are any segments already queued for processing @@ -2354,7 +2385,7 @@ func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool) tcpip.Error { } if nicID != 0 && nicID != e.boundNICID { - return &tcpip.ErrNoRoute{} + return &tcpip.ErrHostUnreachable{} } nicID = e.boundNICID @@ -2776,7 +2807,7 @@ func (e *endpoint) getRemoteAddress() tcpip.FullAddress { } } -func (*endpoint) HandlePacket(stack.TransportEndpointID, *stack.PacketBuffer) { +func (*endpoint) HandlePacket(stack.TransportEndpointID, stack.PacketBufferPtr) { // TCP HandlePacket is not required anymore as inbound packets first // land at the Dispatcher which then can either deliver using the // worker go routine or directly do the invoke the tcp processing inline @@ -2794,7 +2825,7 @@ func (e *endpoint) enqueueSegment(s *segment) bool { return true } -func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, pkt *stack.PacketBuffer) { +func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, pkt stack.PacketBufferPtr) { // Update last error first. e.lastErrorMu.Lock() e.lastError = err @@ -2851,7 +2882,7 @@ func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, p } // HandleError implements stack.TransportEndpoint. -func (e *endpoint) HandleError(transErr stack.TransportError, pkt *stack.PacketBuffer) { +func (e *endpoint) HandleError(transErr stack.TransportError, pkt stack.PacketBufferPtr) { handlePacketTooBig := func(mtu uint32) { e.sndQueueInfo.sndQueueMu.Lock() update := false @@ -2875,7 +2906,7 @@ func (e *endpoint) HandleError(transErr stack.TransportError, pkt *stack.PacketB case stack.PacketTooBigTransportError: handlePacketTooBig(transErr.Info()) case stack.DestinationHostUnreachableTransportError: - e.onICMPError(&tcpip.ErrNoRoute{}, transErr, pkt) + e.onICMPError(&tcpip.ErrHostUnreachable{}, transErr, pkt) case stack.DestinationNetworkUnreachableTransportError: e.onICMPError(&tcpip.ErrNetworkUnreachable{}, transErr, pkt) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/forwarder.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/forwarder.go index b3888ff20..3d632939d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/forwarder.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/forwarder.go @@ -64,7 +64,7 @@ func NewForwarder(s *stack.Stack, rcvWnd, maxInFlight int, handler func(*Forward // // This function is expected to be passed as an argument to the // stack.SetTransportProtocolHandler function. -func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool { +func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) bool { s, err := newIncomingSegment(id, f.stack.Clock(), pkt) if err != nil { return false diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/protocol.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/protocol.go index 500c8ab95..e38ecddea 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/protocol.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/protocol.go @@ -144,7 +144,7 @@ func (*protocol) ParsePorts(v []byte) (src, dst uint16, err tcpip.Error) { // to a specific processing queue. Each queue is serviced by its own processor // goroutine which is responsible for dequeuing and doing full TCP dispatch of // the packet. -func (p *protocol) QueuePacket(ep stack.TransportEndpoint, id stack.TransportEndpointID, pkt *stack.PacketBuffer) { +func (p *protocol) QueuePacket(ep stack.TransportEndpoint, id stack.TransportEndpointID, pkt stack.PacketBufferPtr) { p.dispatcher.queuePacket(ep, id, p.stack.Clock(), pkt) } @@ -155,7 +155,7 @@ func (p *protocol) QueuePacket(ep stack.TransportEndpoint, id stack.TransportEnd // a reset is sent in response to any incoming segment except another reset. In // particular, SYNs addressed to a non-existent connection are rejected by this // means." -func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition { +func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) stack.UnknownDestinationPacketDisposition { s, err := newIncomingSegment(id, p.stack.Clock(), pkt) if err != nil { return stack.UnknownDestinationPacketMalformed @@ -501,7 +501,7 @@ func (p *protocol) Resume() { } // Parse implements stack.TransportProtocol.Parse. -func (*protocol) Parse(pkt *stack.PacketBuffer) bool { +func (*protocol) Parse(pkt stack.PacketBufferPtr) bool { return parse.TCP(pkt) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment.go index 5ea9e8a02..1bb3a490b 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment.go @@ -41,7 +41,7 @@ const ( ) var segmentPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &segment{} }, } @@ -59,7 +59,7 @@ type segment struct { qFlags queueFlags id stack.TransportEndpointID `state:"manual"` - pkt *stack.PacketBuffer + pkt stack.PacketBufferPtr sequenceNumber seqnum.Value ackNumber seqnum.Value @@ -92,16 +92,16 @@ type segment struct { lost bool } -func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) (*segment, error) { +func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt stack.PacketBufferPtr) (*segment, error) { hdr := header.TCP(pkt.TransportHeader().Slice()) netHdr := pkt.Network() csum, csumValid, ok := header.TCPValid( hdr, - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), netHdr.SourceAddress(), netHdr.DestinationAddress(), - pkt.RXTransportChecksumValidated) + pkt.RXChecksumValidated) if !ok { return nil, fmt.Errorf("header data offset does not respect size constraints: %d < offset < %d, got offset=%d", header.TCPMinimumSize, len(hdr), hdr.DataOffset()) } @@ -116,11 +116,10 @@ func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *st s.window = seqnum.Size(hdr.WindowSize()) s.rcvdTime = clock.NowMonotonic() s.dataMemSize = pkt.MemSize() - s.pkt = pkt - pkt.IncRef() + s.pkt = pkt.IncRef() s.csumValid = csumValid - if !s.pkt.RXTransportChecksumValidated { + if !s.pkt.RXChecksumValidated { s.csum = csum } return s, nil @@ -195,7 +194,6 @@ func (s *segment) DecRef() { } } s.pkt.DecRef() - s.pkt = nil segmentPool.Put(s) }) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment_heap.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment_heap.go index 8d3ddce4b..33dcc090a 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment_heap.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/segment_heap.go @@ -36,12 +36,12 @@ func (h *segmentHeap) Swap(i, j int) { } // Push adds x as the last element of h. -func (h *segmentHeap) Push(x interface{}) { +func (h *segmentHeap) Push(x any) { *h = append(*h, x.(*segment)) } // Pop removes the last element of h and returns it. -func (h *segmentHeap) Pop() interface{} { +func (h *segmentHeap) Pop() any { old := *h n := len(old) x := old[n-1] diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/snd.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/snd.go index 3f20cbe21..d762c410e 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/snd.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/snd.go @@ -1660,7 +1660,7 @@ func (s *sender) sendSegment(seg *segment) tcpip.Error { // flags and sequence number. // +checklocks:s.ep.mu // +checklocksalias:s.ep.rcv.ep.mu=s.ep.mu -func (s *sender) sendSegmentFromPacketBuffer(pkt *stack.PacketBuffer, flags header.TCPFlags, seq seqnum.Value) tcpip.Error { +func (s *sender) sendSegmentFromPacketBuffer(pkt stack.PacketBufferPtr, flags header.TCPFlags, seq seqnum.Value) tcpip.Error { s.LastSendTime = s.ep.stack.Clock().NowMonotonic() if seq == s.RTTMeasureSeqNum { s.RTTMeasureTime = s.LastSendTime diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_segment_refs.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_segment_refs.go index b301c3be3..822371b22 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_segment_refs.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_segment_refs.go @@ -4,7 +4,7 @@ import ( "fmt" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/refsvfs2" + "gvisor.dev/gvisor/pkg/refs" ) // enableLogging indicates whether reference-related events should be logged (with @@ -44,20 +44,20 @@ type segmentRefs struct { // checking. func (r *segmentRefs) InitRefs() { r.refCount.Store(1) - refsvfs2.Register(r) + refs.Register(r) } -// RefType implements refsvfs2.CheckedObject.RefType. +// RefType implements refs.CheckedObject.RefType. func (r *segmentRefs) RefType() string { return fmt.Sprintf("%T", segmentobj)[1:] } -// LeakMessage implements refsvfs2.CheckedObject.LeakMessage. +// LeakMessage implements refs.CheckedObject.LeakMessage. func (r *segmentRefs) LeakMessage() string { return fmt.Sprintf("[%s %p] reference count of %d instead of 0", r.RefType(), r, r.ReadRefs()) } -// LogRefs implements refsvfs2.CheckedObject.LogRefs. +// LogRefs implements refs.CheckedObject.LogRefs. func (r *segmentRefs) LogRefs() bool { return segmentenableLogging } @@ -74,7 +74,7 @@ func (r *segmentRefs) ReadRefs() int64 { func (r *segmentRefs) IncRef() { v := r.refCount.Add(1) if segmentenableLogging { - refsvfs2.LogIncRef(r, v) + refs.LogIncRef(r, v) } if v <= 1 { panic(fmt.Sprintf("Incrementing non-positive count %p on %s", r, r.RefType())) @@ -98,7 +98,7 @@ func (r *segmentRefs) TryIncRef() bool { v := r.refCount.Add(-speculativeRef + 1) if segmentenableLogging { - refsvfs2.LogTryIncRef(r, v) + refs.LogTryIncRef(r, v) } return true } @@ -118,14 +118,14 @@ func (r *segmentRefs) TryIncRef() bool { func (r *segmentRefs) DecRef(destroy func()) { v := r.refCount.Add(-1) if segmentenableLogging { - refsvfs2.LogDecRef(r, v) + refs.LogDecRef(r, v) } switch { case v < 0: panic(fmt.Sprintf("Decrementing non-positive ref count %p, owned by %s", r, r.RefType())) case v == 0: - refsvfs2.Unregister(r) + refs.Unregister(r) if destroy != nil { destroy() @@ -135,6 +135,6 @@ func (r *segmentRefs) DecRef(destroy func()) { func (r *segmentRefs) afterLoad() { if r.ReadRefs() > 0 { - refsvfs2.Register(r) + refs.Register(r) } } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_state_autogen.go index 40bc72ca7..912b12a26 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/tcp/tcp_state_autogen.go @@ -36,7 +36,7 @@ func (a *acceptQueue) afterLoad() {} func (a *acceptQueue) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(1, &a.pendingEndpoints) stateSourceObject.Load(2, &a.capacity) - stateSourceObject.LoadValue(0, new([]*endpoint), func(y interface{}) { a.loadEndpoints(y.([]*endpoint)) }) + stateSourceObject.LoadValue(0, new([]*endpoint), func(y any) { a.loadEndpoints(y.([]*endpoint)) }) } func (h *handshake) StateTypeName() string { @@ -492,7 +492,7 @@ func (e *endpoint) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(48, &e.owner) stateSourceObject.Load(49, &e.ops) stateSourceObject.Load(50, &e.lastOutOfWindowAckTime) - stateSourceObject.LoadValue(11, new(EndpointState), func(y interface{}) { e.loadState(y.(EndpointState)) }) + stateSourceObject.LoadValue(11, new(EndpointState), func(y any) { e.loadState(y.(EndpointState)) }) stateSourceObject.AfterLoad(e.afterLoad) } @@ -800,7 +800,7 @@ func (s *segment) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(17, &s.acked) stateSourceObject.Load(18, &s.dataMemSize) stateSourceObject.Load(19, &s.lost) - stateSourceObject.LoadValue(12, new([]byte), func(y interface{}) { s.loadOptions(y.([]byte)) }) + stateSourceObject.LoadValue(12, new([]byte), func(y any) { s.loadOptions(y.([]byte)) }) } func (q *segmentQueue) StateTypeName() string { diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/endpoint.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/endpoint.go index c9a43240f..b3d448b2d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/endpoint.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/endpoint.go @@ -24,6 +24,7 @@ import ( "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/checksum" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/ports" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -39,7 +40,7 @@ type udpPacket struct { senderAddress tcpip.FullAddress destinationAddress tcpip.FullAddress packetInfo tcpip.IPPacketInfo - pkt *stack.PacketBuffer + pkt stack.PacketBufferPtr receivedAt time.Time `state:".(int64)"` // tosOrTClass stores either the Type of Service for IPv4 or the Traffic Class // for IPv6. @@ -352,7 +353,10 @@ var _ tcpip.EndpointWithPreflight = (*endpoint)(nil) // is specified, binds the endpoint to that address. func (e *endpoint) Preflight(opts tcpip.WriteOptions) tcpip.Error { var r bytes.Reader - _, err := e.prepareForWrite(&r, opts) + udpInfo, err := e.prepareForWrite(&r, opts) + if err == nil { + udpInfo.ctx.Release() + } return err } @@ -369,7 +373,7 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp e.stats.WriteErrors.WriteClosed.Increment() case *tcpip.ErrInvalidEndpointState: e.stats.WriteErrors.InvalidEndpointState.Increment() - case *tcpip.ErrNoRoute, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: + case *tcpip.ErrHostUnreachable, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: // Errors indicating any problem with IP routing of the packet. e.stats.SendErrors.NoRoute.Increment() default: @@ -472,7 +476,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp dataSz := udpInfo.data.Size() pktInfo := udpInfo.ctx.PacketInfo() pkt := udpInfo.ctx.TryNewPacketBuffer(header.UDPMinimumSize+int(pktInfo.MaxHeaderLength), udpInfo.data) - if pkt == nil { + if pkt.IsNil() { return 0, &tcpip.ErrWouldBlock{} } defer pkt.DecRef() @@ -494,9 +498,9 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp // On IPv6, UDP checksum is not optional (RFC2460 Section 8.1). if pktInfo.RequiresTXTransportChecksum && (!e.ops.GetNoChecksum() || pktInfo.NetProto == header.IPv6ProtocolNumber) { - xsum := udp.CalculateChecksum(header.ChecksumCombine( + xsum := udp.CalculateChecksum(checksum.Combine( header.PseudoHeaderChecksum(ProtocolNumber, pktInfo.LocalAddress, pktInfo.RemoteAddress, length), - pkt.Data().AsRange().Checksum(), + pkt.Data().Checksum(), )) // As per RFC 768 page 2, // @@ -901,18 +905,18 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask { // HandlePacket is called by the stack when new packets arrive to this transport // endpoint. -func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) { +func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) { // Get the header then trim it from the view. hdr := header.UDP(pkt.TransportHeader().Slice()) netHdr := pkt.Network() lengthValid, csumValid := header.UDPValid( hdr, - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, netHdr.SourceAddress(), netHdr.DestinationAddress(), - pkt.RXTransportChecksumValidated) + pkt.RXChecksumValidated) if !lengthValid { // Malformed packet. e.stack.Stats().UDP.MalformedPacketsReceived.Increment() @@ -993,7 +997,7 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB } } -func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, pkt *stack.PacketBuffer) { +func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, pkt stack.PacketBufferPtr) { // Update last error first. e.lastErrorMu.Lock() e.lastError = err @@ -1041,7 +1045,7 @@ func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, p } // HandleError implements stack.TransportEndpoint. -func (e *endpoint) HandleError(transErr stack.TransportError, pkt *stack.PacketBuffer) { +func (e *endpoint) HandleError(transErr stack.TransportError, pkt stack.PacketBufferPtr) { // TODO(gvisor.dev/issues/5270): Handle all transport errors. switch transErr.Kind() { case stack.DestinationPortUnreachableTransportError: diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/forwarder.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/forwarder.go index 7238fc019..4997fa11c 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/forwarder.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/forwarder.go @@ -43,7 +43,7 @@ func NewForwarder(s *stack.Stack, handler func(*ForwarderRequest)) *Forwarder { // // This function is expected to be passed as an argument to the // stack.SetTransportProtocolHandler function. -func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool { +func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) bool { f.handler(&ForwarderRequest{ stack: f.stack, id: id, @@ -59,7 +59,7 @@ func (f *Forwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Packet type ForwarderRequest struct { stack *stack.Stack id stack.TransportEndpointID - pkt *stack.PacketBuffer + pkt stack.PacketBufferPtr } // ID returns the 4-tuple (src address, src port, dst address, dst port) that diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/protocol.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/protocol.go index 8b4368908..d4de0d2b4 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/protocol.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/protocol.go @@ -77,17 +77,17 @@ func (*protocol) ParsePorts(v []byte) (src, dst uint16, err tcpip.Error) { // HandleUnknownDestinationPacket handles packets that are targeted at this // protocol but don't match any existing endpoint. -func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition { +func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) stack.UnknownDestinationPacketDisposition { hdr := header.UDP(pkt.TransportHeader().Slice()) netHdr := pkt.Network() lengthValid, csumValid := header.UDPValid( hdr, - func() uint16 { return pkt.Data().AsRange().Checksum() }, + func() uint16 { return pkt.Data().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, netHdr.SourceAddress(), netHdr.DestinationAddress(), - pkt.RXTransportChecksumValidated) + pkt.RXChecksumValidated) if !lengthValid { p.stack.Stats().UDP.MalformedPacketsReceived.Increment() return stack.UnknownDestinationPacketMalformed @@ -124,7 +124,7 @@ func (*protocol) Pause() {} func (*protocol) Resume() {} // Parse implements stack.TransportProtocol.Parse. -func (*protocol) Parse(pkt *stack.PacketBuffer) bool { +func (*protocol) Parse(pkt stack.PacketBufferPtr) bool { return parse.UDP(pkt) } diff --git a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/udp_state_autogen.go b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/udp_state_autogen.go index 9a9f371e2..c624ba41d 100644 --- a/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/udp_state_autogen.go +++ b/vendor/gvisor.dev/gvisor/pkg/tcpip/transport/udp/udp_state_autogen.go @@ -54,7 +54,7 @@ func (p *udpPacket) StateLoad(stateSourceObject state.Source) { stateSourceObject.Load(5, &p.pkt) stateSourceObject.Load(7, &p.tosOrTClass) stateSourceObject.Load(8, &p.ttlOrHopLimit) - stateSourceObject.LoadValue(6, new(int64), func(y interface{}) { p.loadReceivedAt(y.(int64)) }) + stateSourceObject.LoadValue(6, new(int64), func(y any) { p.loadReceivedAt(y.(int64)) }) } func (e *endpoint) StateTypeName() string { diff --git a/vendor/modules.txt b/vendor/modules.txt index 0482bae0c..603eb804c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -209,8 +209,8 @@ gopkg.in/tomb.v1 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# gvisor.dev/gvisor v0.0.0-20220908032458-edc830a43ba6 -## explicit; go 1.17 +# gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2 +## explicit; go 1.18 gvisor.dev/gvisor/pkg/atomicbitops gvisor.dev/gvisor/pkg/bits gvisor.dev/gvisor/pkg/bufferv2 @@ -222,13 +222,14 @@ gvisor.dev/gvisor/pkg/linewriter gvisor.dev/gvisor/pkg/log gvisor.dev/gvisor/pkg/rand gvisor.dev/gvisor/pkg/refs -gvisor.dev/gvisor/pkg/refsvfs2 gvisor.dev/gvisor/pkg/sleep gvisor.dev/gvisor/pkg/state gvisor.dev/gvisor/pkg/state/wire gvisor.dev/gvisor/pkg/sync +gvisor.dev/gvisor/pkg/sync/locking gvisor.dev/gvisor/pkg/tcpip gvisor.dev/gvisor/pkg/tcpip/adapters/gonet +gvisor.dev/gvisor/pkg/tcpip/checksum gvisor.dev/gvisor/pkg/tcpip/hash/jenkins gvisor.dev/gvisor/pkg/tcpip/header gvisor.dev/gvisor/pkg/tcpip/header/parse