snapshot: sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
Содержимое пина, зафиксированного в go.mod sing-box-lx, одним коммитом без истории. Полная история SagerNet/gvisor — 1.45 ГБ и клонируется в каждой CI-джобе; наша дельта — одна вставка в одну функцию, история для неё не нужна. Module path github.com/sagernet/gvisor сохранён намеренно: на него опирается replace-директива суперпроекта. Патч поверх — отдельным коммитом, чтобы дельта читалась одним git show и переносилась на новый пин копированием. SPECS/TASKS/048-GVISOR_HANDSHAKE_NIL_CRASH
This commit is contained in:
commit
2c4ae3b0a4
712 changed files with 185689 additions and 0 deletions
116
pkg/xdp/txqueue.go
Normal file
116
pkg/xdp/txqueue.go
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// 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 amd64 || arm64
|
||||
// +build amd64 arm64
|
||||
|
||||
package xdp
|
||||
|
||||
import (
|
||||
"github.com/sagernet/gvisor/pkg/atomicbitops"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// The TXQueue is how a process tells the kernel which buffers are available to
|
||||
// be sent via the NIC.
|
||||
//
|
||||
// TXQueue is not thread-safe and requires external synchronization
|
||||
type TXQueue struct {
|
||||
// sockfd is the underlying AF_XDP socket.
|
||||
sockfd uint32
|
||||
|
||||
// mem is the mmap'd area shared with the kernel. Many other fields of
|
||||
// this struct point into mem.
|
||||
mem []byte
|
||||
|
||||
// ring is the actual ring buffer. It is a list of XDP descriptors
|
||||
// pointing to ready-to-transmit packets.
|
||||
//
|
||||
// len(ring) must be a power of 2.
|
||||
ring []unix.XDPDesc
|
||||
|
||||
// mask is used whenever indexing into ring. It is always len(ring)-1.
|
||||
// It prevents index out of bounds errors while allowing the producer
|
||||
// and consumer pointers to repeatedly "overflow" and loop back around
|
||||
// the ring.
|
||||
mask uint32
|
||||
|
||||
// producer points to the shared atomic value that indicates the last
|
||||
// produced descriptor. Only we update this value.
|
||||
producer *atomicbitops.Uint32
|
||||
|
||||
// consumer points to the shared atomic value that indicates the last
|
||||
// consumed descriptor. Only the kernel updates this value.
|
||||
consumer *atomicbitops.Uint32
|
||||
|
||||
// flags points to the shared atomic value that holds flags for the
|
||||
// queue.
|
||||
flags *atomicbitops.Uint32
|
||||
|
||||
// Cached values are used to avoid relatively expensive atomic
|
||||
// operations. They are used, incremented, and decremented multiple
|
||||
// times with non-atomic operations, and then "batch-updated" by
|
||||
// reading or writing atomically to synchronize with the kernel.
|
||||
|
||||
// cachedProducer is used to atomically write *producer.
|
||||
cachedProducer uint32
|
||||
// cachedConsumer is updated when we atomically read *consumer.
|
||||
// cachedConsumer is actually len(ring) larger than the real consumer
|
||||
// value. See free() for details.
|
||||
cachedConsumer uint32
|
||||
}
|
||||
|
||||
// Reserve reserves descriptors in the queue. If toReserve descriptors cannot
|
||||
// be reserved, none are reserved.
|
||||
//
|
||||
// +checklocks:umem.mu
|
||||
func (tq *TXQueue) Reserve(umem *UMEM, toReserve uint32) (nReserved, index uint32) {
|
||||
if umem.nFreeFrames < toReserve || tq.free(toReserve) < toReserve {
|
||||
return 0, 0
|
||||
}
|
||||
idx := tq.cachedProducer
|
||||
tq.cachedProducer += toReserve
|
||||
return toReserve, idx
|
||||
}
|
||||
|
||||
// free returns the number of free descriptors in the TX queue.
|
||||
func (tq *TXQueue) free(toReserve uint32) uint32 {
|
||||
// Try to find free descriptors without incurring an atomic operation.
|
||||
//
|
||||
// cachedConsumer is always len(tq.ring) larger than the real consumer
|
||||
// value. This lets us, in the common case, compute the number of free
|
||||
// descriptors simply via tq.cachedConsumer - tq.cachedProducer without
|
||||
// also addign len(tq.ring).
|
||||
if available := tq.cachedConsumer - tq.cachedProducer; available >= toReserve {
|
||||
return available
|
||||
}
|
||||
|
||||
// If we didn't already have enough descriptors available, check
|
||||
// whether the kernel has returned some to us.
|
||||
tq.cachedConsumer = tq.consumer.Load()
|
||||
tq.cachedConsumer += uint32(len(tq.ring))
|
||||
return tq.cachedConsumer - tq.cachedProducer
|
||||
}
|
||||
|
||||
// Notify updates the producer such that it is visible to the kernel.
|
||||
func (tq *TXQueue) Notify() {
|
||||
tq.producer.Store(tq.cachedProducer)
|
||||
tq.kick()
|
||||
}
|
||||
|
||||
// Set sets the TX queue's descriptor at index to addr.
|
||||
func (tq *TXQueue) Set(index uint32, desc unix.XDPDesc) {
|
||||
// Use mask to avoid overflowing and loop back around the ring.
|
||||
tq.ring[index&tq.mask] = desc
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue