2022-11-04 13:57:20 +00:00
|
|
|
/*
|
|
|
|
Package rcmgr is the resource manager for go-libp2p. This allows you to track
|
|
|
|
resources being used throughout your go-libp2p process. As well as making sure
|
|
|
|
that the process doesn't use more resources than what you define as your
|
|
|
|
limits. The resource manager only knows about things it is told about, so it's
|
|
|
|
the responsibility of the user of this library (either go-libp2p or a go-libp2p
|
|
|
|
user) to make sure they check with the resource manager before actually
|
|
|
|
allocating the resource.
|
|
|
|
*/
|
2022-04-01 16:16:46 +00:00
|
|
|
package rcmgr
|
|
|
|
|
|
|
|
import (
|
2022-08-19 16:34:07 +00:00
|
|
|
"encoding/json"
|
|
|
|
"io"
|
2023-02-22 21:58:17 +00:00
|
|
|
"math"
|
2022-08-19 16:34:07 +00:00
|
|
|
|
2022-11-04 13:57:20 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/network"
|
|
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
|
|
"github.com/libp2p/go-libp2p/core/protocol"
|
2022-04-01 16:16:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Limit is an object that specifies basic resource limits.
|
|
|
|
type Limit interface {
|
|
|
|
// GetMemoryLimit returns the (current) memory limit.
|
|
|
|
GetMemoryLimit() int64
|
|
|
|
// GetStreamLimit returns the stream limit, for inbound or outbound streams.
|
|
|
|
GetStreamLimit(network.Direction) int
|
|
|
|
// GetStreamTotalLimit returns the total stream limit
|
|
|
|
GetStreamTotalLimit() int
|
|
|
|
// GetConnLimit returns the connection limit, for inbound or outbound connections.
|
|
|
|
GetConnLimit(network.Direction) int
|
|
|
|
// GetConnTotalLimit returns the total connection limit
|
|
|
|
GetConnTotalLimit() int
|
|
|
|
// GetFDLimit returns the file descriptor limit.
|
|
|
|
GetFDLimit() int
|
|
|
|
}
|
|
|
|
|
|
|
|
// Limiter is the interface for providing limits to the resource manager.
|
|
|
|
type Limiter interface {
|
|
|
|
GetSystemLimits() Limit
|
|
|
|
GetTransientLimits() Limit
|
2022-08-19 16:34:07 +00:00
|
|
|
GetAllowlistedSystemLimits() Limit
|
|
|
|
GetAllowlistedTransientLimits() Limit
|
2022-04-01 16:16:46 +00:00
|
|
|
GetServiceLimits(svc string) Limit
|
|
|
|
GetServicePeerLimits(svc string) Limit
|
|
|
|
GetProtocolLimits(proto protocol.ID) Limit
|
|
|
|
GetProtocolPeerLimits(proto protocol.ID) Limit
|
|
|
|
GetPeerLimits(p peer.ID) Limit
|
|
|
|
GetStreamLimits(p peer.ID) Limit
|
|
|
|
GetConnLimits() Limit
|
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
// NewDefaultLimiterFromJSON creates a new limiter by parsing a json configuration,
|
|
|
|
// using the default limits for fallback.
|
|
|
|
func NewDefaultLimiterFromJSON(in io.Reader) (Limiter, error) {
|
|
|
|
return NewLimiterFromJSON(in, DefaultLimits.AutoScale())
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
// NewLimiterFromJSON creates a new limiter by parsing a json configuration.
|
2023-02-22 21:58:17 +00:00
|
|
|
func NewLimiterFromJSON(in io.Reader, defaults ConcreteLimitConfig) (Limiter, error) {
|
2022-08-19 16:34:07 +00:00
|
|
|
cfg, err := readLimiterConfigFromJSON(in, defaults)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &fixedLimiter{cfg}, nil
|
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func readLimiterConfigFromJSON(in io.Reader, defaults ConcreteLimitConfig) (ConcreteLimitConfig, error) {
|
|
|
|
var cfg PartialLimitConfig
|
2022-08-19 16:34:07 +00:00
|
|
|
if err := json.NewDecoder(in).Decode(&cfg); err != nil {
|
2023-02-22 21:58:17 +00:00
|
|
|
return ConcreteLimitConfig{}, err
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
2023-02-22 21:58:17 +00:00
|
|
|
return cfg.Build(defaults), nil
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// fixedLimiter is a limiter with fixed limits.
|
|
|
|
type fixedLimiter struct {
|
2023-02-22 21:58:17 +00:00
|
|
|
ConcreteLimitConfig
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ Limiter = (*fixedLimiter)(nil)
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func NewFixedLimiter(conf ConcreteLimitConfig) Limiter {
|
2022-08-19 16:34:07 +00:00
|
|
|
log.Debugw("initializing new limiter with config", "limits", conf)
|
2023-02-22 21:58:17 +00:00
|
|
|
return &fixedLimiter{conf}
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
2022-04-01 16:16:46 +00:00
|
|
|
|
|
|
|
// BaseLimit is a mixin type for basic resource limits.
|
|
|
|
type BaseLimit struct {
|
2023-02-22 21:58:17 +00:00
|
|
|
Streams int `json:",omitempty"`
|
|
|
|
StreamsInbound int `json:",omitempty"`
|
|
|
|
StreamsOutbound int `json:",omitempty"`
|
|
|
|
Conns int `json:",omitempty"`
|
|
|
|
ConnsInbound int `json:",omitempty"`
|
|
|
|
ConnsOutbound int `json:",omitempty"`
|
|
|
|
FD int `json:",omitempty"`
|
|
|
|
Memory int64 `json:",omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func valueOrBlockAll(n int) LimitVal {
|
|
|
|
if n == 0 {
|
|
|
|
return BlockAllLimit
|
|
|
|
} else if n == math.MaxInt {
|
|
|
|
return Unlimited
|
|
|
|
}
|
|
|
|
return LimitVal(n)
|
|
|
|
}
|
|
|
|
func valueOrBlockAll64(n int64) LimitVal64 {
|
|
|
|
if n == 0 {
|
|
|
|
return BlockAllLimit64
|
|
|
|
} else if n == math.MaxInt {
|
|
|
|
return Unlimited64
|
|
|
|
}
|
|
|
|
return LimitVal64(n)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToResourceLimits converts the BaseLimit to a ResourceLimits
|
|
|
|
func (l BaseLimit) ToResourceLimits() ResourceLimits {
|
|
|
|
return ResourceLimits{
|
|
|
|
Streams: valueOrBlockAll(l.Streams),
|
|
|
|
StreamsInbound: valueOrBlockAll(l.StreamsInbound),
|
|
|
|
StreamsOutbound: valueOrBlockAll(l.StreamsOutbound),
|
|
|
|
Conns: valueOrBlockAll(l.Conns),
|
|
|
|
ConnsInbound: valueOrBlockAll(l.ConnsInbound),
|
|
|
|
ConnsOutbound: valueOrBlockAll(l.ConnsOutbound),
|
|
|
|
FD: valueOrBlockAll(l.FD),
|
|
|
|
Memory: valueOrBlockAll64(l.Memory),
|
|
|
|
}
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
// Apply overwrites all zero-valued limits with the values of l2
|
|
|
|
// Must not use a pointer receiver.
|
|
|
|
func (l *BaseLimit) Apply(l2 BaseLimit) {
|
|
|
|
if l.Streams == 0 {
|
|
|
|
l.Streams = l2.Streams
|
|
|
|
}
|
|
|
|
if l.StreamsInbound == 0 {
|
|
|
|
l.StreamsInbound = l2.StreamsInbound
|
|
|
|
}
|
|
|
|
if l.StreamsOutbound == 0 {
|
|
|
|
l.StreamsOutbound = l2.StreamsOutbound
|
|
|
|
}
|
|
|
|
if l.Conns == 0 {
|
|
|
|
l.Conns = l2.Conns
|
|
|
|
}
|
|
|
|
if l.ConnsInbound == 0 {
|
|
|
|
l.ConnsInbound = l2.ConnsInbound
|
|
|
|
}
|
|
|
|
if l.ConnsOutbound == 0 {
|
|
|
|
l.ConnsOutbound = l2.ConnsOutbound
|
|
|
|
}
|
|
|
|
if l.Memory == 0 {
|
|
|
|
l.Memory = l2.Memory
|
|
|
|
}
|
|
|
|
if l.FD == 0 {
|
|
|
|
l.FD = l2.FD
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 13:57:20 +00:00
|
|
|
// BaseLimitIncrease is the increase per GiB of allowed memory.
|
2022-08-19 16:34:07 +00:00
|
|
|
type BaseLimitIncrease struct {
|
2023-02-22 21:58:17 +00:00
|
|
|
Streams int `json:",omitempty"`
|
|
|
|
StreamsInbound int `json:",omitempty"`
|
|
|
|
StreamsOutbound int `json:",omitempty"`
|
|
|
|
Conns int `json:",omitempty"`
|
|
|
|
ConnsInbound int `json:",omitempty"`
|
|
|
|
ConnsOutbound int `json:",omitempty"`
|
2022-11-04 13:57:20 +00:00
|
|
|
// Memory is in bytes. Values over 1>>30 (1GiB) don't make sense.
|
2023-02-22 21:58:17 +00:00
|
|
|
Memory int64 `json:",omitempty"`
|
2022-11-04 13:57:20 +00:00
|
|
|
// FDFraction is expected to be >= 0 and <= 1.
|
2023-02-22 21:58:17 +00:00
|
|
|
FDFraction float64 `json:",omitempty"`
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Apply overwrites all zero-valued limits with the values of l2
|
|
|
|
// Must not use a pointer receiver.
|
|
|
|
func (l *BaseLimitIncrease) Apply(l2 BaseLimitIncrease) {
|
|
|
|
if l.Streams == 0 {
|
|
|
|
l.Streams = l2.Streams
|
|
|
|
}
|
|
|
|
if l.StreamsInbound == 0 {
|
|
|
|
l.StreamsInbound = l2.StreamsInbound
|
|
|
|
}
|
|
|
|
if l.StreamsOutbound == 0 {
|
|
|
|
l.StreamsOutbound = l2.StreamsOutbound
|
|
|
|
}
|
|
|
|
if l.Conns == 0 {
|
|
|
|
l.Conns = l2.Conns
|
|
|
|
}
|
|
|
|
if l.ConnsInbound == 0 {
|
|
|
|
l.ConnsInbound = l2.ConnsInbound
|
|
|
|
}
|
|
|
|
if l.ConnsOutbound == 0 {
|
|
|
|
l.ConnsOutbound = l2.ConnsOutbound
|
|
|
|
}
|
|
|
|
if l.Memory == 0 {
|
|
|
|
l.Memory = l2.Memory
|
|
|
|
}
|
|
|
|
if l.FDFraction == 0 {
|
|
|
|
l.FDFraction = l2.FDFraction
|
|
|
|
}
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func (l BaseLimit) GetStreamLimit(dir network.Direction) int {
|
2022-04-01 16:16:46 +00:00
|
|
|
if dir == network.DirInbound {
|
|
|
|
return l.StreamsInbound
|
|
|
|
} else {
|
|
|
|
return l.StreamsOutbound
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func (l BaseLimit) GetStreamTotalLimit() int {
|
2022-04-01 16:16:46 +00:00
|
|
|
return l.Streams
|
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func (l BaseLimit) GetConnLimit(dir network.Direction) int {
|
2022-04-01 16:16:46 +00:00
|
|
|
if dir == network.DirInbound {
|
|
|
|
return l.ConnsInbound
|
|
|
|
} else {
|
|
|
|
return l.ConnsOutbound
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func (l BaseLimit) GetConnTotalLimit() int {
|
2022-04-01 16:16:46 +00:00
|
|
|
return l.Conns
|
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func (l BaseLimit) GetFDLimit() int {
|
2022-04-01 16:16:46 +00:00
|
|
|
return l.FD
|
|
|
|
}
|
|
|
|
|
2023-02-22 21:58:17 +00:00
|
|
|
func (l BaseLimit) GetMemoryLimit() int64 {
|
2022-08-19 16:34:07 +00:00
|
|
|
return l.Memory
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetSystemLimits() Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.system
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetTransientLimits() Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.transient
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetAllowlistedSystemLimits() Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.allowlistedSystem
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (l *fixedLimiter) GetAllowlistedTransientLimits() Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.allowlistedTransient
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetServiceLimits(svc string) Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
sl, ok := l.service[svc]
|
2022-04-01 16:16:46 +00:00
|
|
|
if !ok {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.serviceDefault
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
2022-08-19 16:34:07 +00:00
|
|
|
return &sl
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetServicePeerLimits(svc string) Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
pl, ok := l.servicePeer[svc]
|
2022-04-01 16:16:46 +00:00
|
|
|
if !ok {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.servicePeerDefault
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
2022-08-19 16:34:07 +00:00
|
|
|
return &pl
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetProtocolLimits(proto protocol.ID) Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
pl, ok := l.protocol[proto]
|
2022-04-01 16:16:46 +00:00
|
|
|
if !ok {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.protocolDefault
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
2022-08-19 16:34:07 +00:00
|
|
|
return &pl
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetProtocolPeerLimits(proto protocol.ID) Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
pl, ok := l.protocolPeer[proto]
|
2022-08-19 16:34:07 +00:00
|
|
|
if !ok {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.protocolPeerDefault
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
|
|
|
return &pl
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetPeerLimits(p peer.ID) Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
pl, ok := l.peer[p]
|
2022-08-19 16:34:07 +00:00
|
|
|
if !ok {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.peerDefault
|
2022-08-19 16:34:07 +00:00
|
|
|
}
|
|
|
|
return &pl
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetStreamLimits(_ peer.ID) Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.stream
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 16:34:07 +00:00
|
|
|
func (l *fixedLimiter) GetConnLimits() Limit {
|
2023-02-22 21:58:17 +00:00
|
|
|
return &l.conn
|
2022-04-01 16:16:46 +00:00
|
|
|
}
|