Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v0.17.0 #9430

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .circleci/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ jobs:
docker:
- image: cimg/go:1.19.1-node
parallelism: 4
resource_class: large
resource_class: 2xlarge+
steps:
- *make_out_dirs
- attach_workspace:
Expand Down Expand Up @@ -324,6 +324,7 @@ jobs:
- ~/.cache/go-build/
ipfs-webui:
executor: node-browsers
resource_class: 2xlarge+
steps:
- *make_out_dirs
- attach_workspace:
Expand Down
12 changes: 4 additions & 8 deletions config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@ func InitWithIdentity(identity Identity) (*Config, error) {
Interval: "12h",
Strategy: "all",
},
Swarm: SwarmConfig{
ConnMgr: ConnMgr{
LowWater: DefaultConnMgrLowWater,
HighWater: DefaultConnMgrHighWater,
GracePeriod: DefaultConnMgrGracePeriod.String(),
Type: "basic",
},
},
Pinning: Pinning{
RemoteServices: map[string]RemotePinningService{},
},
Expand Down Expand Up @@ -114,6 +106,10 @@ const DefaultConnMgrLowWater = 600
// grace period
const DefaultConnMgrGracePeriod = time.Second * 20

// DefaultConnMgrType is the default value for the connection managers
// type.
const DefaultConnMgrType = "basic"

func addressesConfig() Addresses {
return Addresses{
Swarm: []string{
Expand Down
10 changes: 7 additions & 3 deletions config/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,13 @@ fetching may be degraded.
c.AutoNAT.ServiceMode = AutoNATServiceDisabled
c.Reprovider.Interval = "0"

c.Swarm.ConnMgr.LowWater = 20
c.Swarm.ConnMgr.HighWater = 40
c.Swarm.ConnMgr.GracePeriod = time.Minute.String()
lowWater := int64(20)
highWater := int64(40)
gracePeriod := time.Minute
c.Swarm.ConnMgr.Type = NewOptionalString("basic")
c.Swarm.ConnMgr.LowWater = &OptionalInteger{value: &lowWater}
c.Swarm.ConnMgr.HighWater = &OptionalInteger{value: &highWater}
c.Swarm.ConnMgr.GracePeriod = &OptionalDuration{&gracePeriod}
return nil
},
},
Expand Down
12 changes: 6 additions & 6 deletions config/swarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ type Transports struct {

// ConnMgr defines configuration options for the libp2p connection manager
type ConnMgr struct {
Type string
LowWater int
HighWater int
GracePeriod string
Type *OptionalString `json:",omitempty"`
LowWater *OptionalInteger `json:",omitempty"`
HighWater *OptionalInteger `json:",omitempty"`
GracePeriod *OptionalDuration `json:",omitempty"`
}

// ResourceMgr defines configuration options for the libp2p Network Resource Manager
Expand All @@ -144,8 +144,8 @@ type ResourceMgr struct {
Enabled Flag `json:",omitempty"`
Limits *rcmgr.LimitConfig `json:",omitempty"`

MaxMemory OptionalString `json:",omitempty"`
MaxFileDescriptors OptionalInteger `json:",omitempty"`
MaxMemory *OptionalString `json:",omitempty"`
MaxFileDescriptors *OptionalInteger `json:",omitempty"`

// A list of multiaddrs that can bypass normal system limits (but are still
// limited by the allowlist scope). Convenience config around
Expand Down
39 changes: 13 additions & 26 deletions core/node/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,20 @@ var BaseLibP2P = fx.Options(
)

func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
// parse ConnMgr config

grace := config.DefaultConnMgrGracePeriod
low := config.DefaultConnMgrLowWater
high := config.DefaultConnMgrHighWater

connmgr := fx.Options()

if cfg.Swarm.ConnMgr.Type != "none" {
switch cfg.Swarm.ConnMgr.Type {
case "":
// 'default' value is the basic connection manager
break
case "basic":
var err error
grace, err = time.ParseDuration(cfg.Swarm.ConnMgr.GracePeriod)
if err != nil {
return fx.Error(fmt.Errorf("parsing Swarm.ConnMgr.GracePeriod: %s", err))
}

low = cfg.Swarm.ConnMgr.LowWater
high = cfg.Swarm.ConnMgr.HighWater
default:
return fx.Error(fmt.Errorf("unrecognized ConnMgr.Type: %q", cfg.Swarm.ConnMgr.Type))
}

var connmgr fx.Option

// set connmgr based on Swarm.ConnMgr.Type
connMgrType := cfg.Swarm.ConnMgr.Type.WithDefault(config.DefaultConnMgrType)
switch connMgrType {
case "none":
connmgr = fx.Options() // noop
case "", "basic":
grace := cfg.Swarm.ConnMgr.GracePeriod.WithDefault(config.DefaultConnMgrGracePeriod)
low := int(cfg.Swarm.ConnMgr.LowWater.WithDefault(config.DefaultConnMgrLowWater))
high := int(cfg.Swarm.ConnMgr.HighWater.WithDefault(config.DefaultConnMgrHighWater))
connmgr = fx.Provide(libp2p.ConnectionManager(low, high, grace))
default:
return fx.Error(fmt.Errorf("unrecognized Swarm.ConnMgr.Type: %q", connMgrType))
}

// parse PubSub config
Expand Down
12 changes: 8 additions & 4 deletions core/node/libp2p/rcmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,22 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
return nil, opts, fmt.Errorf("opening IPFS_PATH: %w", err)
}

limits, err := createDefaultLimitConfig(cfg)
limitConfig, err := createDefaultLimitConfig(cfg)
if err != nil {
return nil, opts, err
}

// The logic for defaults and overriding with specified SwarmConfig.ResourceMgr.Limits
// is documented in docs/config.md.
// Any changes here should be reflected there.
if cfg.ResourceMgr.Limits != nil {
l := *cfg.ResourceMgr.Limits
l.Apply(limits)
limits = l
// This effectively overrides the computed default LimitConfig with any vlues from cfg.ResourceMgr.Limits
l.Apply(limitConfig)
limitConfig = l
}

limiter := rcmgr.NewFixedLimiter(limits)
limiter := rcmgr.NewFixedLimiter(limitConfig)

str, err := rcmgrObs.NewStatsTraceReporter()
if err != nil {
Expand Down
83 changes: 27 additions & 56 deletions core/node/libp2p/rcmgr_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,51 +44,8 @@ var noLimitIncrease = rcmgr.BaseLimitIncrease{
// This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled

// createDefaultLimitConfig creates LimitConfig to pass to libp2p's resource manager.
// libp2p's resource manager provides tremendous flexibility but also adds a lot of complexity.
// The intent of the default config here is to provide good defaults,
// and where the defaults aren't good enough,
// to expose a good set of higher-level "knobs" to users to satisfy most use cases
// without requiring users to wade into all the intricacies of libp2p's resource manager.
//
// The inputs one can specify in SwarmConfig are:
// - cfg.ResourceMgr.MaxMemory: This is the max amount of memory in bytes to allow libp2p to use.
// libp2p's resource manager will prevent additional resource creation while this limit is hit.
// If this value isn't specified, 1/8th of the total system memory is used.
// - cfg.ResourceMgr.MaxFileDescriptors: This is the maximum number of file descriptors to allow libp2p to use.
// libp2p's resource manager will prevent additional file descriptor consumption while this limit is hit.
// If this value isn't specified, the maximum between 1/2 of system FD limit and 4096 is used.
// - Swarm.ConnMgr.HighWater: If a connection manager is specified, libp2p's resource manager
// will allow 2x more connections than the HighWater mark
// so the connection manager has "space and time" to close "least useful" connections.
//
// With these inputs defined, limits are created at the system, transient, and peer scopes.
// Other scopes are ignored (by being set to infinity).
// The reason these scopes are chosen is because:
// - system - This gives us the coarse-grained control we want so we can reason about the system as a whole.
// It is the backstop, and allows us to reason about resource consumption more easily
// since don't have think about the interaction of many other scopes.
// - transient - Limiting connections that are in process of being established provides backpressure so not too much work queues up.
// - peer - The peer scope doesn't protect us against intentional DoS attacks.
// It's just as easy for an attacker to send 100 requests/second with 1 peerId vs. 10 requests/second with 10 peers.
// We are reliant on the system scope for protection here in the malicious case.
// The reason for having a peer scope is to protect against unintentional DoS attacks
// (e.g., bug in a peer which is causing it to "misbehave").
// In the unintional case, we want to make sure a "misbehaving" node doesn't consume more resources than necessary.
//
// Within these scopes, limits are just set on memory, FD, and inbound connections/streams.
// Limits are set based on the inputs above.
// We trust this node to behave properly and thus ignore outbound connection/stream limits.
// We apply any limits that libp2p has for its protocols/services
// since we assume libp2p knows best here.
//
// This leaves 3 levels of resource management protection:
// 1. The user who does nothing and uses defaults - In this case they get some sane defaults
// based on the amount of memory and file descriptors their system has.
// This should protect the node from many attacks.
// 2. Slightly more advanced user - They can tweak the above by passing in config on
// maxMemory, maxFD, or maxConns with Swarm.HighWater.ConnMgr.
// 3. Power user - They specify all the limits they want set via Swarm.ResourceMgr.Limits
// and we don't do any defaults/overrides. We pass that config blindly into libp2p resource manager.
// The defaults follow the documentation in docs/config.md.
// Any changes in the logic here should be reflected there.
func createDefaultLimitConfig(cfg config.SwarmConfig) (rcmgr.LimitConfig, error) {
maxMemoryDefaultString := humanize.Bytes(uint64(memory.TotalMemory()) / 8)
maxMemoryString := cfg.ResourceMgr.MaxMemory.WithDefault(maxMemoryDefaultString)
Expand All @@ -105,7 +62,6 @@ func createDefaultLimitConfig(cfg config.SwarmConfig) (rcmgr.LimitConfig, error)
FD: int(numFD),

// By default, we just limit connections on the inbound side.
// Note that the limit gets adjusted below if "cfg.ConnMgr.HighWater" is set.
Conns: bigEnough,
ConnsInbound: rcmgr.DefaultLimits.SystemBaseLimit.ConnsInbound, // same as libp2p default
ConnsOutbound: bigEnough,
Expand All @@ -132,9 +88,31 @@ func createDefaultLimitConfig(cfg config.SwarmConfig) (rcmgr.LimitConfig, error)
StreamsOutbound: 0,
},

// Just go with what libp2p does
TransientBaseLimit: rcmgr.DefaultLimits.TransientBaseLimit,
TransientLimitIncrease: rcmgr.DefaultLimits.TransientLimitIncrease,
TransientBaseLimit: rcmgr.BaseLimit{
Memory: rcmgr.DefaultLimits.TransientBaseLimit.Memory,
FD: rcmgr.DefaultLimits.TransientBaseLimit.FD,

Conns: bigEnough,
ConnsInbound: rcmgr.DefaultLimits.TransientBaseLimit.ConnsInbound,
ConnsOutbound: bigEnough,

Streams: bigEnough,
StreamsInbound: rcmgr.DefaultLimits.TransientBaseLimit.StreamsInbound,
StreamsOutbound: bigEnough,
},

TransientLimitIncrease: rcmgr.BaseLimitIncrease{
Memory: rcmgr.DefaultLimits.TransientLimitIncrease.Memory,
FDFraction: rcmgr.DefaultLimits.TransientLimitIncrease.FDFraction,

Conns: 0,
ConnsInbound: rcmgr.DefaultLimits.TransientLimitIncrease.ConnsInbound,
ConnsOutbound: 0,

Streams: 0,
StreamsInbound: rcmgr.DefaultLimits.TransientLimitIncrease.StreamsInbound,
StreamsOutbound: 0,
},

// Lets get out of the way of the allow list functionality.
// If someone specified "Swarm.ResourceMgr.Allowlist" we should let it go through.
Expand Down Expand Up @@ -197,12 +175,5 @@ func createDefaultLimitConfig(cfg config.SwarmConfig) (rcmgr.LimitConfig, error)

defaultLimitConfig := scalingLimitConfig.Scale(int64(maxMemory), int(numFD))

// If a high water mark is set:
if cfg.ConnMgr.Type == "basic" {
// set the connection limit higher than high water mark so that the ConnMgr has "space and time" to close "least useful" connections.
defaultLimitConfig.System.Conns = 2 * cfg.ConnMgr.HighWater
log.Info("adjusted default resource manager System.Conns limits to match ConnMgr.HighWater value of %s", cfg.ConnMgr.HighWater)
}

return defaultLimitConfig, nil
}
Loading