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
137
pkg/tcpip/network/internal/multicast/multicast_state_autogen.go
Normal file
137
pkg/tcpip/network/internal/multicast/multicast_state_autogen.go
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// automatically generated by stateify.
|
||||
|
||||
package multicast
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/state"
|
||||
)
|
||||
|
||||
func (r *RouteTable) StateTypeName() string {
|
||||
return "pkg/tcpip/network/internal/multicast.RouteTable"
|
||||
}
|
||||
|
||||
func (r *RouteTable) StateFields() []string {
|
||||
return []string{
|
||||
"installedRoutes",
|
||||
"pendingRoutes",
|
||||
"cleanupPendingRoutesTimer",
|
||||
"isCleanupRoutineRunning",
|
||||
"config",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RouteTable) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (r *RouteTable) StateSave(stateSinkObject state.Sink) {
|
||||
r.beforeSave()
|
||||
stateSinkObject.Save(0, &r.installedRoutes)
|
||||
stateSinkObject.Save(1, &r.pendingRoutes)
|
||||
stateSinkObject.Save(2, &r.cleanupPendingRoutesTimer)
|
||||
stateSinkObject.Save(3, &r.isCleanupRoutineRunning)
|
||||
stateSinkObject.Save(4, &r.config)
|
||||
}
|
||||
|
||||
func (r *RouteTable) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (r *RouteTable) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &r.installedRoutes)
|
||||
stateSourceObject.Load(1, &r.pendingRoutes)
|
||||
stateSourceObject.Load(2, &r.cleanupPendingRoutesTimer)
|
||||
stateSourceObject.Load(3, &r.isCleanupRoutineRunning)
|
||||
stateSourceObject.Load(4, &r.config)
|
||||
}
|
||||
|
||||
func (r *InstalledRoute) StateTypeName() string {
|
||||
return "pkg/tcpip/network/internal/multicast.InstalledRoute"
|
||||
}
|
||||
|
||||
func (r *InstalledRoute) StateFields() []string {
|
||||
return []string{
|
||||
"MulticastRoute",
|
||||
"lastUsedTimestamp",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InstalledRoute) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (r *InstalledRoute) StateSave(stateSinkObject state.Sink) {
|
||||
r.beforeSave()
|
||||
stateSinkObject.Save(0, &r.MulticastRoute)
|
||||
stateSinkObject.Save(1, &r.lastUsedTimestamp)
|
||||
}
|
||||
|
||||
func (r *InstalledRoute) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (r *InstalledRoute) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &r.MulticastRoute)
|
||||
stateSourceObject.Load(1, &r.lastUsedTimestamp)
|
||||
}
|
||||
|
||||
func (p *PendingRoute) StateTypeName() string {
|
||||
return "pkg/tcpip/network/internal/multicast.PendingRoute"
|
||||
}
|
||||
|
||||
func (p *PendingRoute) StateFields() []string {
|
||||
return []string{
|
||||
"packets",
|
||||
"expiration",
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PendingRoute) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (p *PendingRoute) StateSave(stateSinkObject state.Sink) {
|
||||
p.beforeSave()
|
||||
stateSinkObject.Save(0, &p.packets)
|
||||
stateSinkObject.Save(1, &p.expiration)
|
||||
}
|
||||
|
||||
func (p *PendingRoute) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (p *PendingRoute) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &p.packets)
|
||||
stateSourceObject.Load(1, &p.expiration)
|
||||
}
|
||||
|
||||
func (c *Config) StateTypeName() string {
|
||||
return "pkg/tcpip/network/internal/multicast.Config"
|
||||
}
|
||||
|
||||
func (c *Config) StateFields() []string {
|
||||
return []string{
|
||||
"MaxPendingQueueSize",
|
||||
"Clock",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (c *Config) StateSave(stateSinkObject state.Sink) {
|
||||
c.beforeSave()
|
||||
stateSinkObject.Save(0, &c.MaxPendingQueueSize)
|
||||
stateSinkObject.Save(1, &c.Clock)
|
||||
}
|
||||
|
||||
func (c *Config) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (c *Config) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &c.MaxPendingQueueSize)
|
||||
stateSourceObject.Load(1, &c.Clock)
|
||||
}
|
||||
|
||||
func init() {
|
||||
state.Register((*RouteTable)(nil))
|
||||
state.Register((*InstalledRoute)(nil))
|
||||
state.Register((*PendingRoute)(nil))
|
||||
state.Register((*Config)(nil))
|
||||
}
|
||||
446
pkg/tcpip/network/internal/multicast/route_table.go
Normal file
446
pkg/tcpip/network/internal/multicast/route_table.go
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
// 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 multicast contains utilities for supporting multicast routing.
|
||||
package multicast
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// RouteTable represents a multicast routing table.
|
||||
//
|
||||
// +stateify savable
|
||||
type RouteTable struct {
|
||||
// Internally, installed and pending routes are stored and locked separately
|
||||
// A couple of reasons for structuring the table this way:
|
||||
//
|
||||
// 1. We can avoid write locking installed routes when pending packets are
|
||||
// being queued. In other words, the happy path of reading installed
|
||||
// routes doesn't require an exclusive lock.
|
||||
// 2. The cleanup process for expired routes only needs to operate on pending
|
||||
// routes. Like above, a write lock on the installed routes can be
|
||||
// avoided.
|
||||
// 3. This structure is similar to the Linux implementation:
|
||||
// https://github.com/torvalds/linux/blob/cffb2b72d3e/include/linux/mroute_base.h#L250
|
||||
|
||||
// The installedMu lock should typically be acquired before the pendingMu
|
||||
// lock. This ensures that installed routes can continue to be read even when
|
||||
// the pending routes are write locked.
|
||||
|
||||
installedMu sync.RWMutex `state:"nosave"`
|
||||
// Maintaining pointers ensures that the installed routes are exclusively
|
||||
// locked only when a route is being installed.
|
||||
// +checklocks:installedMu
|
||||
installedRoutes map[stack.UnicastSourceAndMulticastDestination]*InstalledRoute
|
||||
|
||||
pendingMu sync.RWMutex `state:"nosave"`
|
||||
// +checklocks:pendingMu
|
||||
pendingRoutes map[stack.UnicastSourceAndMulticastDestination]PendingRoute
|
||||
// cleanupPendingRoutesTimer is a timer that triggers a routine to remove
|
||||
// pending routes that are expired.
|
||||
// +checklocks:pendingMu
|
||||
cleanupPendingRoutesTimer tcpip.Timer
|
||||
// +checklocks:pendingMu
|
||||
isCleanupRoutineRunning bool
|
||||
|
||||
config Config
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrNoBufferSpace indicates that no buffer space is available in the
|
||||
// pending route packet queue.
|
||||
ErrNoBufferSpace = errors.New("unable to queue packet, no buffer space available")
|
||||
|
||||
// ErrMissingClock indicates that a clock was not provided as part of the
|
||||
// Config, but is required.
|
||||
ErrMissingClock = errors.New("clock must not be nil")
|
||||
|
||||
// ErrAlreadyInitialized indicates that RouteTable.Init was already invoked.
|
||||
ErrAlreadyInitialized = errors.New("table is already initialized")
|
||||
)
|
||||
|
||||
// InstalledRoute represents a route that is in the installed state.
|
||||
//
|
||||
// If a route is in the installed state, then it may be used to forward
|
||||
// multicast packets.
|
||||
//
|
||||
// +stateify savable
|
||||
type InstalledRoute struct {
|
||||
stack.MulticastRoute
|
||||
|
||||
lastUsedTimestampMu sync.RWMutex `state:"nosave"`
|
||||
// +checklocks:lastUsedTimestampMu
|
||||
lastUsedTimestamp tcpip.MonotonicTime
|
||||
}
|
||||
|
||||
// LastUsedTimestamp returns a monotonic timestamp that corresponds to the last
|
||||
// time the route was used or updated.
|
||||
func (r *InstalledRoute) LastUsedTimestamp() tcpip.MonotonicTime {
|
||||
r.lastUsedTimestampMu.RLock()
|
||||
defer r.lastUsedTimestampMu.RUnlock()
|
||||
|
||||
return r.lastUsedTimestamp
|
||||
}
|
||||
|
||||
// SetLastUsedTimestamp sets the time that the route was last used.
|
||||
//
|
||||
// The timestamp is only updated if it occurs after the currently set
|
||||
// timestamp. Callers should invoke this anytime the route is used to forward a
|
||||
// packet.
|
||||
func (r *InstalledRoute) SetLastUsedTimestamp(monotonicTime tcpip.MonotonicTime) {
|
||||
r.lastUsedTimestampMu.Lock()
|
||||
defer r.lastUsedTimestampMu.Unlock()
|
||||
|
||||
if monotonicTime.After(r.lastUsedTimestamp) {
|
||||
r.lastUsedTimestamp = monotonicTime
|
||||
}
|
||||
}
|
||||
|
||||
// PendingRoute represents a route that is in the "pending" state.
|
||||
//
|
||||
// A route is in the pending state if an installed route does not yet exist
|
||||
// for the entry. For such routes, packets are added to an expiring queue until
|
||||
// a route is installed.
|
||||
//
|
||||
// +stateify savable
|
||||
type PendingRoute struct {
|
||||
packets []*stack.PacketBuffer
|
||||
|
||||
// expiration is the timestamp at which the pending route should be expired.
|
||||
//
|
||||
// If this value is before the current time, then this pending route will
|
||||
// be dropped.
|
||||
expiration tcpip.MonotonicTime
|
||||
}
|
||||
|
||||
func (p *PendingRoute) releasePackets() {
|
||||
for _, pkt := range p.packets {
|
||||
pkt.DecRef()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PendingRoute) isExpired(currentTime tcpip.MonotonicTime) bool {
|
||||
return currentTime.After(p.expiration)
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultMaxPendingQueueSize corresponds to the number of elements that can
|
||||
// be in the packet queue for a pending route.
|
||||
//
|
||||
// Matches the Linux default queue size:
|
||||
// https://github.com/torvalds/linux/blob/26291c54e11/net/ipv6/ip6mr.c#L1186
|
||||
DefaultMaxPendingQueueSize uint8 = 3
|
||||
|
||||
// DefaultPendingRouteExpiration is the default maximum lifetime of a pending
|
||||
// route.
|
||||
//
|
||||
// Matches the Linux default:
|
||||
// https://github.com/torvalds/linux/blob/26291c54e11/net/ipv6/ip6mr.c#L991
|
||||
DefaultPendingRouteExpiration time.Duration = 10 * time.Second
|
||||
|
||||
// DefaultCleanupInterval is the default frequency of the routine that
|
||||
// expires pending routes.
|
||||
//
|
||||
// Matches the Linux default:
|
||||
// https://github.com/torvalds/linux/blob/26291c54e11/net/ipv6/ip6mr.c#L793
|
||||
DefaultCleanupInterval time.Duration = 10 * time.Second
|
||||
)
|
||||
|
||||
// Config represents the options for configuring a RouteTable.
|
||||
//
|
||||
// +stateify savable
|
||||
type Config struct {
|
||||
// MaxPendingQueueSize corresponds to the maximum number of queued packets
|
||||
// for a pending route.
|
||||
//
|
||||
// If the caller attempts to queue a packet and the queue already contains
|
||||
// MaxPendingQueueSize elements, then the packet will be rejected and should
|
||||
// not be forwarded.
|
||||
MaxPendingQueueSize uint8
|
||||
|
||||
// Clock represents the clock that should be used to obtain the current time.
|
||||
//
|
||||
// This field is required and must have a non-nil value.
|
||||
Clock tcpip.Clock
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default configuration for the table.
|
||||
func DefaultConfig(clock tcpip.Clock) Config {
|
||||
return Config{
|
||||
MaxPendingQueueSize: DefaultMaxPendingQueueSize,
|
||||
Clock: clock,
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the RouteTable with the provided config.
|
||||
//
|
||||
// An error is returned if the config is not valid.
|
||||
//
|
||||
// Must be called before any other function on the table.
|
||||
func (r *RouteTable) Init(config Config) error {
|
||||
r.installedMu.Lock()
|
||||
defer r.installedMu.Unlock()
|
||||
r.pendingMu.Lock()
|
||||
defer r.pendingMu.Unlock()
|
||||
|
||||
if r.installedRoutes != nil {
|
||||
return ErrAlreadyInitialized
|
||||
}
|
||||
|
||||
if config.Clock == nil {
|
||||
return ErrMissingClock
|
||||
}
|
||||
|
||||
r.config = config
|
||||
r.installedRoutes = make(map[stack.UnicastSourceAndMulticastDestination]*InstalledRoute)
|
||||
r.pendingRoutes = make(map[stack.UnicastSourceAndMulticastDestination]PendingRoute)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close cleans up resources held by the table.
|
||||
//
|
||||
// Calling this will stop the cleanup routine and release any packets owned by
|
||||
// the table.
|
||||
func (r *RouteTable) Close() {
|
||||
r.pendingMu.Lock()
|
||||
defer r.pendingMu.Unlock()
|
||||
|
||||
if r.cleanupPendingRoutesTimer != nil {
|
||||
r.cleanupPendingRoutesTimer.Stop()
|
||||
}
|
||||
|
||||
for key, route := range r.pendingRoutes {
|
||||
delete(r.pendingRoutes, key)
|
||||
route.releasePackets()
|
||||
}
|
||||
}
|
||||
|
||||
// maybeStopCleanupRoutine stops the pending routes cleanup routine if no
|
||||
// pending routes exist.
|
||||
//
|
||||
// Returns true if the timer is not running. Otherwise, returns false.
|
||||
//
|
||||
// +checklocks:r.pendingMu
|
||||
func (r *RouteTable) maybeStopCleanupRoutineLocked() bool {
|
||||
if !r.isCleanupRoutineRunning {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(r.pendingRoutes) == 0 {
|
||||
r.cleanupPendingRoutesTimer.Stop()
|
||||
r.isCleanupRoutineRunning = false
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *RouteTable) cleanupPendingRoutes() {
|
||||
currentTime := r.config.Clock.NowMonotonic()
|
||||
r.pendingMu.Lock()
|
||||
defer r.pendingMu.Unlock()
|
||||
|
||||
for key, route := range r.pendingRoutes {
|
||||
if route.isExpired(currentTime) {
|
||||
delete(r.pendingRoutes, key)
|
||||
route.releasePackets()
|
||||
}
|
||||
}
|
||||
|
||||
if stopped := r.maybeStopCleanupRoutineLocked(); !stopped {
|
||||
r.cleanupPendingRoutesTimer.Reset(DefaultCleanupInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RouteTable) newPendingRoute() PendingRoute {
|
||||
return PendingRoute{
|
||||
packets: make([]*stack.PacketBuffer, 0, r.config.MaxPendingQueueSize),
|
||||
expiration: r.config.Clock.NowMonotonic().Add(DefaultPendingRouteExpiration),
|
||||
}
|
||||
}
|
||||
|
||||
// NewInstalledRoute instantiates an installed route for the table.
|
||||
func (r *RouteTable) NewInstalledRoute(route stack.MulticastRoute) *InstalledRoute {
|
||||
return &InstalledRoute{
|
||||
MulticastRoute: route,
|
||||
lastUsedTimestamp: r.config.Clock.NowMonotonic(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetRouteResult represents the result of calling GetRouteOrInsertPending.
|
||||
type GetRouteResult struct {
|
||||
// GetRouteResultState signals the result of calling GetRouteOrInsertPending.
|
||||
GetRouteResultState GetRouteResultState
|
||||
|
||||
// InstalledRoute represents the existing installed route. This field will
|
||||
// only be populated if the GetRouteResultState is InstalledRouteFound.
|
||||
InstalledRoute *InstalledRoute
|
||||
}
|
||||
|
||||
// GetRouteResultState signals the result of calling GetRouteOrInsertPending.
|
||||
type GetRouteResultState uint8
|
||||
|
||||
const (
|
||||
// InstalledRouteFound indicates that an InstalledRoute was found.
|
||||
InstalledRouteFound GetRouteResultState = iota
|
||||
|
||||
// PacketQueuedInPendingRoute indicates that the packet was queued in an
|
||||
// existing pending route.
|
||||
PacketQueuedInPendingRoute
|
||||
|
||||
// NoRouteFoundAndPendingInserted indicates that no route was found and that
|
||||
// a pending route was newly inserted into the RouteTable.
|
||||
NoRouteFoundAndPendingInserted
|
||||
)
|
||||
|
||||
func (e GetRouteResultState) String() string {
|
||||
switch e {
|
||||
case InstalledRouteFound:
|
||||
return "InstalledRouteFound"
|
||||
case PacketQueuedInPendingRoute:
|
||||
return "PacketQueuedInPendingRoute"
|
||||
case NoRouteFoundAndPendingInserted:
|
||||
return "NoRouteFoundAndPendingInserted"
|
||||
default:
|
||||
return fmt.Sprintf("%d", uint8(e))
|
||||
}
|
||||
}
|
||||
|
||||
// GetRouteOrInsertPending attempts to fetch the installed route that matches
|
||||
// the provided key.
|
||||
//
|
||||
// If no matching installed route is found, then the pkt is cloned and queued
|
||||
// in a pending route. The GetRouteResult.GetRouteResultState will indicate
|
||||
// whether the pkt was queued in a new pending route or an existing one.
|
||||
//
|
||||
// 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) {
|
||||
r.installedMu.RLock()
|
||||
defer r.installedMu.RUnlock()
|
||||
|
||||
if route, ok := r.installedRoutes[key]; ok {
|
||||
return GetRouteResult{GetRouteResultState: InstalledRouteFound, InstalledRoute: route}, true
|
||||
}
|
||||
|
||||
r.pendingMu.Lock()
|
||||
defer r.pendingMu.Unlock()
|
||||
|
||||
pendingRoute, getRouteResultState := r.getOrCreatePendingRouteRLocked(key)
|
||||
if len(pendingRoute.packets) >= int(r.config.MaxPendingQueueSize) {
|
||||
// The incoming packet is rejected if the pending queue is already at max
|
||||
// capacity. This behavior matches the Linux implementation:
|
||||
// https://github.com/torvalds/linux/blob/ae085d7f936/net/ipv4/ipmr.c#L1147
|
||||
return GetRouteResult{}, false
|
||||
}
|
||||
pendingRoute.packets = append(pendingRoute.packets, pkt.Clone())
|
||||
r.pendingRoutes[key] = pendingRoute
|
||||
|
||||
if !r.isCleanupRoutineRunning {
|
||||
// The cleanup routine isn't running, but should be. Start it.
|
||||
if r.cleanupPendingRoutesTimer == nil {
|
||||
r.cleanupPendingRoutesTimer = r.config.Clock.AfterFunc(DefaultCleanupInterval, r.cleanupPendingRoutes)
|
||||
} else {
|
||||
r.cleanupPendingRoutesTimer.Reset(DefaultCleanupInterval)
|
||||
}
|
||||
r.isCleanupRoutineRunning = true
|
||||
}
|
||||
|
||||
return GetRouteResult{GetRouteResultState: getRouteResultState, InstalledRoute: nil}, true
|
||||
}
|
||||
|
||||
// +checklocks:r.pendingMu
|
||||
func (r *RouteTable) getOrCreatePendingRouteRLocked(key stack.UnicastSourceAndMulticastDestination) (PendingRoute, GetRouteResultState) {
|
||||
if pendingRoute, ok := r.pendingRoutes[key]; ok {
|
||||
return pendingRoute, PacketQueuedInPendingRoute
|
||||
}
|
||||
return r.newPendingRoute(), NoRouteFoundAndPendingInserted
|
||||
}
|
||||
|
||||
// AddInstalledRoute adds the provided route to the table.
|
||||
//
|
||||
// Packets that were queued while the route was in the pending state are
|
||||
// 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 {
|
||||
r.installedMu.Lock()
|
||||
defer r.installedMu.Unlock()
|
||||
r.installedRoutes[key] = route
|
||||
|
||||
r.pendingMu.Lock()
|
||||
pendingRoute, ok := r.pendingRoutes[key]
|
||||
delete(r.pendingRoutes, key)
|
||||
// No need to reset the timer here. The cleanup routine is responsible for
|
||||
// doing so.
|
||||
_ = r.maybeStopCleanupRoutineLocked()
|
||||
r.pendingMu.Unlock()
|
||||
|
||||
// Ignore the pending route if it is expired. It may be in this state since
|
||||
// the cleanup process is only run periodically.
|
||||
if !ok || pendingRoute.isExpired(r.config.Clock.NowMonotonic()) {
|
||||
pendingRoute.releasePackets()
|
||||
return nil
|
||||
}
|
||||
|
||||
return pendingRoute.packets
|
||||
}
|
||||
|
||||
// RemoveInstalledRoute deletes any installed route that matches the provided
|
||||
// key.
|
||||
//
|
||||
// Returns true if a route was removed. Otherwise returns false.
|
||||
func (r *RouteTable) RemoveInstalledRoute(key stack.UnicastSourceAndMulticastDestination) bool {
|
||||
r.installedMu.Lock()
|
||||
defer r.installedMu.Unlock()
|
||||
|
||||
if _, ok := r.installedRoutes[key]; ok {
|
||||
delete(r.installedRoutes, key)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveAllInstalledRoutes removes all installed routes from the table.
|
||||
func (r *RouteTable) RemoveAllInstalledRoutes() {
|
||||
r.installedMu.Lock()
|
||||
defer r.installedMu.Unlock()
|
||||
|
||||
for key := range r.installedRoutes {
|
||||
delete(r.installedRoutes, key)
|
||||
}
|
||||
}
|
||||
|
||||
// GetLastUsedTimestamp returns a monotonic timestamp that represents the last
|
||||
// time the route that matches the provided key was used or updated.
|
||||
//
|
||||
// Returns true if a matching route was found. Otherwise returns false.
|
||||
func (r *RouteTable) GetLastUsedTimestamp(key stack.UnicastSourceAndMulticastDestination) (tcpip.MonotonicTime, bool) {
|
||||
r.installedMu.RLock()
|
||||
defer r.installedMu.RUnlock()
|
||||
|
||||
if route, ok := r.installedRoutes[key]; ok {
|
||||
return route.LastUsedTimestamp(), true
|
||||
}
|
||||
return tcpip.MonotonicTime{}, false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue