@cryptotaxi247 / kubo / commits / 254d81a9d

feat: Improve ResourceManager UX (#9338)

This PR adds several new functionalities to make easier the usage of ResourceManager: - Now resource manager logs when resources are exceeded are on ERROR instead of warning. - The resources exceeded error now shows what kind of limit was reached and the scope. - When there was no limit exceeded, we print a message for the user saying that limits are not exceeded anymore. - Added `swarm limit all` command to show all set limits with the same format as `swarm stats all` - Added `min-used-limit-perc` option to `swarm stats all` to only show stats that are above a specific percentage - Simplify a lot default values. - **Enable ResourceManager by default.** Output example: ``` 2022-11-09T10:51:40.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:51:50.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 483095 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:51:50.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:52:00.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 455294 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:00.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:52:10.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 471384 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:10.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:52:20.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 8 times with error "peer:12D3KooWKqcaBtcmZKLKCCoDPBuA6AXGJMNrLQUPPMsA5Q6D1eG6: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:20.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 192 times with error "peer:12D3KooWPjetWPGQUih9LZTGHdyAM9fKaXtUxDyBhA93E3JAWCXj: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:20.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 469746 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:20.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:52:30.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 484137 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:30.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 29 times with error "peer:12D3KooWPjetWPGQUih9LZTGHdyAM9fKaXtUxDyBhA93E3JAWCXj: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:30.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:52:40.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 468843 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:40.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:52:50.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 366638 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:52:50.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:53:00.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 405526 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:53:00.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 107 times with error "peer:12D3KooWQZQCwevTDGhkE9iGYk5sBzWRDUSX68oyrcfM9tXyrs2Q: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:53:00.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:53:10.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 336923 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:53:10.566+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:53:20.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:55 Resource limits were exceeded 71 times with error "transient: cannot reserve inbound stream: resource limit exceeded". 2022-11-09T10:53:20.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:59 Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr 2022-11-09T10:53:30.565+0100 ERROR resourcemanager libp2p/rcmgr_logging.go:64 Resrouce limits are no longer being exceeded. ``` ## Validation tests - Accelerated DHT client runs with no errors when ResourceManager is active. No problems were observed. - Running an attack with 200 connections and 1M streams using yamux protocol. Node was usable during the attack. With ResourceManager deactivated, the node was killed by the OS because of the amount of memory consumed. - Actions done when the attack was active: - Add files - Force a reprovide - Use the gateway to resolve an IPNS address. It closes #9001 It closes #9351 It closes #9322

Antonio Navarro Perez committed Nov 10, 2022 at 12:25 UTC 254d81a9d5595c3e637c7573d56125836d5f5055
17 files changed +482 -905
.circleci/main.yml
-1
@@ -32,7 +32,6 @@ default_environment: &default_environment
32 CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
33 CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
34 GIT_PAGER: cat
35 - IPFS_CHECK_RCMGR_DEFAULTS: 1
35
36 executors:
37 golang:
config/swarm.go
+4
@@ -143,6 +143,10 @@ type ResourceMgr struct {
143 // Enables the Network Resource Manager feature, default to on.
144 Enabled Flag `json:",omitempty"`
145 Limits *rcmgr.LimitConfig `json:",omitempty"`
146 +
147 + MaxMemory OptionalString `json:",omitempty"`
148 + MaxFileDescriptors OptionalInteger `json:",omitempty"`
149 +
150 // A list of multiaddrs that can bypass normal system limits (but are still
151 // limited by the allowlist scope). Convenience config around
152 // https://pkg.go.dev/github.com/libp2p/go-libp2p/p2p/host/resource-manager#Allowlist.Add
core/commands/swarm.go
+20 -13
@@ -63,11 +63,12 @@ ipfs peers in the internet.
63 }
64
65 const (
66 - swarmVerboseOptionName = "verbose"
67 - swarmStreamsOptionName = "streams"
68 - swarmLatencyOptionName = "latency"
69 - swarmDirectionOptionName = "direction"
70 - swarmResetLimitsOptionName = "reset"
66 + swarmVerboseOptionName = "verbose"
67 + swarmStreamsOptionName = "streams"
68 + swarmLatencyOptionName = "latency"
69 + swarmDirectionOptionName = "direction"
70 + swarmResetLimitsOptionName = "reset"
71 + swarmUsedResourcesPercentageName = "min-used-limit-perc"
72 )
73
74 type peeringResult struct {
@@ -340,6 +341,9 @@ The output of this command is JSON.
341 Arguments: []cmds.Argument{
342 cmds.StringArg("scope", true, false, "scope of the stat report"),
343 },
344 + Options: []cmds.Option{
345 + cmds.IntOption(swarmUsedResourcesPercentageName, "Display only resources that are using above the specified percentage"),
346 + },
347 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
348 node, err := cmdenv.GetNode(env)
349 if err != nil {
@@ -353,8 +357,10 @@ The output of this command is JSON.
357 if len(req.Arguments) != 1 {
358 return fmt.Errorf("must specify exactly one scope")
359 }
360 +
361 + percentage, _ := req.Options[swarmUsedResourcesPercentageName].(int)
362 scope := req.Arguments[0]
357 - result, err := libp2p.NetStat(node.ResourceManager, scope)
363 + result, err := libp2p.NetStat(node.ResourceManager, scope, percentage)
364 if err != nil {
365 return err
366 }
@@ -378,6 +384,7 @@ var swarmLimitCmd = &cmds.Command{
384 Tagline: "Get or set resource limits for a scope.",
385 LongDescription: `Get or set resource limits for a scope.
386 The scope can be one of the following:
387 +- all -- all limits actually being applied.
388 - system -- limits for the system aggregate resource usage.
389 - transient -- limits for the transient resource usage.
390 - svc:<service> -- limits for the resource usage of a specific service.
@@ -435,19 +442,19 @@ Changes made via command line are persisted in the Swarm.ResourceMgr.Limits fiel
442 }
443 }
444
438 - var result rcmgr.BaseLimit
445 + var result interface{}
446 _, reset := req.Options[swarmResetLimitsOptionName]
447 if reset {
448 result, err = libp2p.NetResetLimit(node.ResourceManager, node.Repo, scope)
442 - if err != nil {
443 - return err
444 - }
449 + } else if scope == "all" {
450 + result, err = libp2p.NetLimitAll(node.ResourceManager)
451 } else {
452 // get scope limit
453 result, err = libp2p.NetLimit(node.ResourceManager, scope)
448 - if err != nil {
449 - return err
450 - }
454 + }
455 +
456 + if err != nil {
457 + return err
458 }
459
460 b := new(bytes.Buffer)
core/node/libp2p/fd/sys_not_unix.go new
+7
@@ -0,0 +1,7 @@
1 +//go:build !linux && !darwin && !windows
2 +
3 +package fd
4 +
5 +func GetNumFDs() int {
6 + return 0
7 +}
core/node/libp2p/fd/sys_unix.go new
+16
@@ -0,0 +1,16 @@
1 +//go:build linux || darwin
2 +// +build linux darwin
3 +
4 +package fd
5 +
6 +import (
7 + "golang.org/x/sys/unix"
8 +)
9 +
10 +func GetNumFDs() int {
11 + var l unix.Rlimit
12 + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &l); err != nil {
13 + return 0
14 + }
15 + return int(l.Cur)
16 +}
core/node/libp2p/fd/sys_windows.go new
+11
@@ -0,0 +1,11 @@
1 +//go:build windows
2 +
3 +package fd
4 +
5 +import (
6 + "math"
7 +)
8 +
9 +func GetNumFDs() int {
10 + return math.MaxInt
11 +}
core/node/libp2p/rcmgr.go
+178 -29
@@ -9,10 +9,6 @@ import (
9
10 "github.com/benbjohnson/clock"
11 logging "github.com/ipfs/go-log/v2"
12 - config "github.com/ipfs/kubo/config"
13 - "github.com/ipfs/kubo/core/node/helpers"
14 - "github.com/ipfs/kubo/repo"
15 -
12 "github.com/libp2p/go-libp2p"
13 "github.com/libp2p/go-libp2p/core/network"
14 "github.com/libp2p/go-libp2p/core/peer"
@@ -21,8 +17,11 @@ import (
17 rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs"
18 "github.com/multiformats/go-multiaddr"
19 "go.opencensus.io/stats/view"
24 -
20 "go.uber.org/fx"
21 +
22 + config "github.com/ipfs/kubo/config"
23 + "github.com/ipfs/kubo/core/node/helpers"
24 + "github.com/ipfs/kubo/repo"
25 )
26
27 const NetLimitDefaultFilename = "limit.json"
@@ -35,7 +34,7 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
34 var manager network.ResourceManager
35 var opts Libp2pOpts
36
38 - enabled := cfg.ResourceMgr.Enabled.WithDefault(false)
37 + enabled := cfg.ResourceMgr.Enabled.WithDefault(true)
38
39 // ENV overrides Config (if present)
40 switch os.Getenv("LIBP2P_RCMGR") {
@@ -53,7 +52,10 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
52 return nil, opts, fmt.Errorf("opening IPFS_PATH: %w", err)
53 }
54
56 - limits := adjustedDefaultLimits(cfg)
55 + limits, err := createDefaultLimitConfig(cfg)
56 + if err != nil {
57 + return nil, opts, err
58 + }
59
60 if cfg.ResourceMgr.Limits != nil {
61 l := *cfg.ResourceMgr.Limits
@@ -122,14 +124,14 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
124 }
125
126 type NetStatOut struct {
125 - System *network.ScopeStat `json:",omitempty"`
126 - Transient *network.ScopeStat `json:",omitempty"`
127 - Services map[string]network.ScopeStat `json:",omitempty"`
128 - Protocols map[string]network.ScopeStat `json:",omitempty"`
129 - Peers map[string]network.ScopeStat `json:",omitempty"`
127 + System *rcmgr.BaseLimit `json:",omitempty"`
128 + Transient *rcmgr.BaseLimit `json:",omitempty"`
129 + Services map[string]rcmgr.BaseLimit `json:",omitempty"`
130 + Protocols map[string]rcmgr.BaseLimit `json:",omitempty"`
131 + Peers map[string]rcmgr.BaseLimit `json:",omitempty"`
132 }
133
132 -func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
134 +func NetStat(mgr network.ResourceManager, scope string, percentage int) (NetStatOut, error) {
135 var err error
136 var result NetStatOut
137 switch {
@@ -139,22 +141,42 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
141 return result, ErrNoResourceMgr
142 }
143
144 + limits, err := NetLimitAll(mgr)
145 + if err != nil {
146 + return result, err
147 + }
148 +
149 stat := rapi.Stat()
143 - result.System = &stat.System
144 - result.Transient = &stat.Transient
150 + result.System = compareLimits(scopeToLimit(&stat.System), limits.System, percentage)
151 + result.Transient = compareLimits(scopeToLimit(&stat.Transient), limits.Transient, percentage)
152 if len(stat.Services) > 0 {
146 - result.Services = stat.Services
153 + result.Services = make(map[string]rcmgr.BaseLimit, len(stat.Services))
154 + for srv, stat := range stat.Services {
155 + ls := limits.Services[srv]
156 + fstat := compareLimits(scopeToLimit(&stat), &ls, percentage)
157 + if fstat != nil {
158 + result.Services[srv] = *fstat
159 + }
160 + }
161 }
162 if len(stat.Protocols) > 0 {
149 - result.Protocols = make(map[string]network.ScopeStat, len(stat.Protocols))
163 + result.Protocols = make(map[string]rcmgr.BaseLimit, len(stat.Protocols))
164 for proto, stat := range stat.Protocols {
151 - result.Protocols[string(proto)] = stat
165 + ls := limits.Protocols[string(proto)]
166 + fstat := compareLimits(scopeToLimit(&stat), &ls, percentage)
167 + if fstat != nil {
168 + result.Protocols[string(proto)] = *fstat
169 + }
170 }
171 }
172 if len(stat.Peers) > 0 {
155 - result.Peers = make(map[string]network.ScopeStat, len(stat.Peers))
173 + result.Peers = make(map[string]rcmgr.BaseLimit, len(stat.Peers))
174 for p, stat := range stat.Peers {
157 - result.Peers[p.Pretty()] = stat
175 + ls := limits.Peers[p.Pretty()]
176 + fstat := compareLimits(scopeToLimit(&stat), &ls, percentage)
177 + if fstat != nil {
178 + result.Peers[p.Pretty()] = *fstat
179 + }
180 }
181 }
182
@@ -163,7 +185,7 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
185 case scope == config.ResourceMgrSystemScope:
186 err = mgr.ViewSystem(func(s network.ResourceScope) error {
187 stat := s.Stat()
166 - result.System = &stat
188 + result.System = scopeToLimit(&stat)
189 return nil
190 })
191 return result, err
@@ -171,7 +193,7 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
193 case scope == config.ResourceMgrTransientScope:
194 err = mgr.ViewTransient(func(s network.ResourceScope) error {
195 stat := s.Stat()
174 - result.Transient = &stat
196 + result.Transient = scopeToLimit(&stat)
197 return nil
198 })
199 return result, err
@@ -180,8 +202,8 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
202 svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix)
203 err = mgr.ViewService(svc, func(s network.ServiceScope) error {
204 stat := s.Stat()
183 - result.Services = map[string]network.ScopeStat{
184 - svc: stat,
205 + result.Services = map[string]rcmgr.BaseLimit{
206 + svc: *scopeToLimit(&stat),
207 }
208 return nil
209 })
@@ -191,8 +213,8 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
213 proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix)
214 err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error {
215 stat := s.Stat()
194 - result.Protocols = map[string]network.ScopeStat{
195 - proto: stat,
216 + result.Protocols = map[string]rcmgr.BaseLimit{
217 + proto: *scopeToLimit(&stat),
218 }
219 return nil
220 })
@@ -206,8 +228,8 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
228 }
229 err = mgr.ViewPeer(pid, func(s network.PeerScope) error {
230 stat := s.Stat()
209 - result.Peers = map[string]network.ScopeStat{
210 - p: stat,
231 + result.Peers = map[string]rcmgr.BaseLimit{
232 + p: *scopeToLimit(&stat),
233 }
234 return nil
235 })
@@ -218,6 +240,130 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
240 }
241 }
242
243 +var scopes = []string{
244 + config.ResourceMgrSystemScope,
245 + config.ResourceMgrTransientScope,
246 + config.ResourceMgrServiceScopePrefix,
247 + config.ResourceMgrProtocolScopePrefix,
248 + config.ResourceMgrPeerScopePrefix,
249 +}
250 +
251 +func scopeToLimit(s *network.ScopeStat) *rcmgr.BaseLimit {
252 + return &rcmgr.BaseLimit{
253 + Streams: s.NumStreamsInbound + s.NumStreamsOutbound,
254 + StreamsInbound: s.NumStreamsInbound,
255 + StreamsOutbound: s.NumStreamsOutbound,
256 + Conns: s.NumConnsInbound + s.NumConnsOutbound,
257 + ConnsInbound: s.NumConnsInbound,
258 + ConnsOutbound: s.NumConnsOutbound,
259 + FD: s.NumFD,
260 + Memory: s.Memory,
261 + }
262 +}
263 +
264 +// compareLimits compares stat and limit.
265 +// If any of the stats value are equals or above the specified percentage,
266 +// stat object is returned.
267 +func compareLimits(stat, limit *rcmgr.BaseLimit, percentage int) *rcmgr.BaseLimit {
268 + if stat == nil || limit == nil {
269 + return nil
270 + }
271 + if abovePercentage(int(stat.Memory), int(limit.Memory), percentage) {
272 + return stat
273 + }
274 + if abovePercentage(stat.ConnsInbound, limit.ConnsInbound, percentage) {
275 + return stat
276 + }
277 + if abovePercentage(stat.ConnsOutbound, limit.ConnsOutbound, percentage) {
278 + return stat
279 + }
280 + if abovePercentage(stat.Conns, limit.Conns, percentage) {
281 + return stat
282 + }
283 + if abovePercentage(stat.FD, limit.FD, percentage) {
284 + return stat
285 + }
286 + if abovePercentage(stat.StreamsInbound, limit.StreamsInbound, percentage) {
287 + return stat
288 + }
289 + if abovePercentage(stat.StreamsOutbound, limit.StreamsOutbound, percentage) {
290 + return stat
291 + }
292 + if abovePercentage(stat.Streams, limit.Streams, percentage) {
293 + return stat
294 + }
295 +
296 + return nil
297 +}
298 +
299 +func abovePercentage(v1, v2, percentage int) bool {
300 + if percentage == 0 {
301 + return true
302 + }
303 +
304 + if v2 == 0 {
305 + return false
306 + }
307 +
308 + return int((v1/v2))*100 >= percentage
309 +}
310 +
311 +func NetLimitAll(mgr network.ResourceManager) (*NetStatOut, error) {
312 + var result = &NetStatOut{}
313 + lister, ok := mgr.(rcmgr.ResourceManagerState)
314 + if !ok { // NullResourceManager
315 + return result, ErrNoResourceMgr
316 + }
317 +
318 + for _, s := range scopes {
319 + switch s {
320 + case config.ResourceMgrSystemScope:
321 + s, err := NetLimit(mgr, config.ResourceMgrSystemScope)
322 + if err != nil {
323 + return nil, err
324 + }
325 + result.System = &s
326 + case config.ResourceMgrTransientScope:
327 + s, err := NetLimit(mgr, config.ResourceMgrSystemScope)
328 + if err != nil {
329 + return nil, err
330 + }
331 + result.Transient = &s
332 + case config.ResourceMgrServiceScopePrefix:
333 + result.Services = make(map[string]rcmgr.BaseLimit)
334 + for _, serv := range lister.ListServices() {
335 + s, err := NetLimit(mgr, config.ResourceMgrServiceScopePrefix+serv)
336 + if err != nil {
337 + return nil, err
338 + }
339 + result.Services[serv] = s
340 + }
341 + case config.ResourceMgrProtocolScopePrefix:
342 + result.Protocols = make(map[string]rcmgr.BaseLimit)
343 + for _, prot := range lister.ListProtocols() {
344 + ps := string(prot)
345 + s, err := NetLimit(mgr, config.ResourceMgrProtocolScopePrefix+ps)
346 + if err != nil {
347 + return nil, err
348 + }
349 + result.Protocols[ps] = s
350 + }
351 + case config.ResourceMgrPeerScopePrefix:
352 + result.Peers = make(map[string]rcmgr.BaseLimit)
353 + for _, peer := range lister.ListPeers() {
354 + ps := peer.Pretty()
355 + s, err := NetLimit(mgr, config.ResourceMgrPeerScopePrefix+ps)
356 + if err != nil {
357 + return nil, err
358 + }
359 + result.Peers[ps] = s
360 + }
361 + }
362 + }
363 +
364 + return result, nil
365 +}
366 +
367 func NetLimit(mgr network.ResourceManager, scope string) (rcmgr.BaseLimit, error) {
368 var result rcmgr.BaseLimit
369 getLimit := func(s network.ResourceScope) error {
@@ -367,7 +513,10 @@ func NetResetLimit(mgr network.ResourceManager, repo repo.Repo, scope string) (r
513 return result, fmt.Errorf("reading config to reset limit: %w", err)
514 }
515
370 - defaults := adjustedDefaultLimits(cfg.Swarm)
516 + defaults, err := createDefaultLimitConfig(cfg.Swarm)
517 + if err != nil {
518 + return result, fmt.Errorf("creating default limit config: %w", err)
519 + }
520
521 if cfg.Swarm.ResourceMgr.Limits == nil {
522 cfg.Swarm.ResourceMgr.Limits = &rcmgr.LimitConfig{}
core/node/libp2p/rcmgr_defaults.go
+185 -809
@@ -1,832 +1,208 @@
1 package libp2p
2
3 import (
4 - "encoding/json"
5 - "fmt"
6 - "math/bits"
7 - "os"
8 - "strings"
4 + "math"
5
10 - "github.com/ipfs/kubo/config"
6 + "github.com/dustin/go-humanize"
7 "github.com/libp2p/go-libp2p"
8 rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
9 + "github.com/pbnjay/memory"
10
14 - "github.com/wI2L/jsondiff"
11 + "github.com/ipfs/kubo/config"
12 + "github.com/ipfs/kubo/core/node/libp2p/fd"
13 )
14
17 -// This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled
18 -
19 -// adjustedDefaultLimits allows for tweaking defaults based on external factors,
20 -// such as values in Swarm.ConnMgr.HiWater config.
21 -func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.LimitConfig {
22 - // Run checks to avoid introducing regressions
23 - if os.Getenv("IPFS_CHECK_RCMGR_DEFAULTS") != "" {
24 - checkImplicitDefaults()
25 - }
26 - defaultLimits := rcmgr.DefaultLimits
27 - libp2p.SetDefaultServiceLimits(&defaultLimits)
28 -
29 - // Adjust limits
30 - // (based on https://github.com/filecoin-project/lotus/pull/8318/files)
31 - // - if Swarm.ConnMgr.HighWater is too high, adjust Conn/FD/Stream limits
32 -
33 - // Outbound conns and FDs are set very high to allow for the accelerated DHT client to (re)load its routing table.
34 - // Currently it doesn't gracefully handle RM throttling--once it does we can lower these.
35 - // High outbound conn limits are considered less of a DoS risk than high inbound conn limits.
36 - // Also note that, due to the behavior of the accelerated DHT client, we don't need many streams, just conns.
37 - if minOutbound := 65536; defaultLimits.SystemBaseLimit.ConnsOutbound < minOutbound {
38 - defaultLimits.SystemBaseLimit.ConnsOutbound = minOutbound
39 - }
40 - if minFD := 4096; defaultLimits.SystemBaseLimit.FD < minFD {
41 - defaultLimits.SystemBaseLimit.FD = minFD
42 - }
43 - defaultLimitConfig := defaultLimits.AutoScale()
44 -
45 - // Do we need to adjust due to Swarm.ConnMgr.HighWater?
46 - if cfg.ConnMgr.Type == "basic" {
47 - maxconns := cfg.ConnMgr.HighWater
48 - if 2*maxconns > defaultLimitConfig.System.ConnsInbound {
49 - // adjust conns to 2x to allow for two conns per peer (TCP+QUIC)
50 - defaultLimitConfig.System.ConnsInbound = logScale(2 * maxconns)
51 - defaultLimitConfig.System.ConnsOutbound = logScale(2 * maxconns)
52 - defaultLimitConfig.System.Conns = logScale(4 * maxconns)
53 -
54 - defaultLimitConfig.System.StreamsInbound = logScale(16 * maxconns)
55 - defaultLimitConfig.System.StreamsOutbound = logScale(64 * maxconns)
56 - defaultLimitConfig.System.Streams = logScale(64 * maxconns)
57 -
58 - if 2*maxconns > defaultLimitConfig.System.FD {
59 - defaultLimitConfig.System.FD = logScale(2 * maxconns)
60 - }
61 -
62 - defaultLimitConfig.ServiceDefault.StreamsInbound = logScale(8 * maxconns)
63 - defaultLimitConfig.ServiceDefault.StreamsOutbound = logScale(32 * maxconns)
64 - defaultLimitConfig.ServiceDefault.Streams = logScale(32 * maxconns)
65 -
66 - defaultLimitConfig.ProtocolDefault.StreamsInbound = logScale(8 * maxconns)
67 - defaultLimitConfig.ProtocolDefault.StreamsOutbound = logScale(32 * maxconns)
68 - defaultLimitConfig.ProtocolDefault.Streams = logScale(32 * maxconns)
69 -
70 - log.Info("adjusted default resource manager limits")
71 - }
72 -
73 - }
74 -
75 - return defaultLimitConfig
15 +// We are doing some magic when parsing config files (we are using a map[string]interface{} to compare config files).
16 +// When you don't have a type the JSON Parse function cast numbers to float64 by default,
17 +// losing precision when writing the final number. So if we use math.MaxInt as our infinite number,
18 +// after writing the config file we will have 9223372036854776000 instead of 9223372036854775807,
19 +// making the parsing process fail.
20 +const bigEnough = math.MaxInt / 2
21 +
22 +var infiniteBaseLimit = rcmgr.BaseLimit{
23 + Streams: bigEnough,
24 + StreamsInbound: bigEnough,
25 + StreamsOutbound: bigEnough,
26 + Conns: bigEnough,
27 + ConnsInbound: bigEnough,
28 + ConnsOutbound: bigEnough,
29 + FD: bigEnough,
30 + Memory: bigEnough,
31 }
32
78 -func logScale(val int) int {
79 - bitlen := bits.Len(uint(val))
80 - return 1 << bitlen
33 +var noLimitIncrease = rcmgr.BaseLimitIncrease{
34 + ConnsInbound: 0,
35 + ConnsOutbound: 0,
36 + Conns: 0,
37 + StreamsInbound: 0,
38 + StreamsOutbound: 0,
39 + Streams: 0,
40 + Memory: 0,
41 + FDFraction: 0,
42 }
43
83 -// checkImplicitDefaults compares libp2p defaults agains expected ones
84 -// and panics when they don't match. This ensures we are not surprised
85 -// by silent default limit changes when we update go-libp2p dependencies.
86 -func checkImplicitDefaults() {
87 - ok := true
44 +// This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled
45
89 - // Check 1: did go-libp2p-resource-manager's DefaultLimits change?
90 - defaults, err := json.Marshal(rcmgr.DefaultLimits)
46 +// createDefaultLimitConfig creates LimitConfig to pass to libp2p's resource manager.
47 +// libp2p's resource manager provides tremendous flexibility but also adds a lot of complexity.
48 +// The intent of the default config here is to provide good defaults,
49 +// and where the defaults aren't good enough,
50 +// to expose a good set of higher-level "knobs" to users to satisfy most use cases
51 +// without requiring users to wade into all the intricacies of libp2p's resource manager.
52 +//
53 +// The inputs one can specify in SwarmConfig are:
54 +// - cfg.ResourceMgr.MaxMemory: This is the max amount of memory in bytes to allow libp2p to use.
55 +// libp2p's resource manager will prevent additional resource creation while this limit is hit.
56 +// If this value isn't specified, 1/8th of the total system memory is used.
57 +// - cfg.ResourceMgr.MaxFileDescriptors: This is the maximum number of file descriptors to allow libp2p to use.
58 +// libp2p's resource manager will prevent additional file descriptor consumption while this limit is hit.
59 +// If this value isn't specified, the maximum between 1/2 of system FD limit and 4096 is used.
60 +// - Swarm.ConnMgr.HighWater: If a connection manager is specified, libp2p's resource manager
61 +// will allow 2x more connections than the HighWater mark
62 +// so the connection manager has "space and time" to close "least useful" connections.
63 +//
64 +// With these inputs defined, limits are created at the system, transient, and peer scopes.
65 +// Other scopes are ignored (by being set to infinity).
66 +// The reason these scopes are chosen is because:
67 +// - system - This gives us the coarse-grained control we want so we can reason about the system as a whole.
68 +// It is the backstop, and allows us to reason about resource consumption more easily
69 +// since don't have think about the interaction of many other scopes.
70 +// - transient - Limiting connections that are in process of being established provides backpressure so not too much work queues up.
71 +// - peer - The peer scope doesn't protect us against intentional DoS attacks.
72 +// It's just as easy for an attacker to send 100 requests/second with 1 peerId vs. 10 requests/second with 10 peers.
73 +// We are reliant on the system scope for protection here in the malicious case.
74 +// The reason for having a peer scope is to protect against unintentional DoS attacks
75 +// (e.g., bug in a peer which is causing it to "misbehave").
76 +// In the unintional case, we want to make sure a "misbehaving" node doesn't consume more resources than necessary.
77 +//
78 +// Within these scopes, limits are just set on memory, FD, and inbound connections/streams.
79 +// Limits are set based on the inputs above.
80 +// We trust this node to behave properly and thus ignore outbound connection/stream limits.
81 +// We apply any limits that libp2p has for its protocols/services
82 +// since we assume libp2p knows best here.
83 +//
84 +// This leaves 3 levels of resource management protection:
85 +// 1. The user who does nothing and uses defaults - In this case they get some sane defaults
86 +// based on the amount of memory and file descriptors their system has.
87 +// This should protect the node from many attacks.
88 +// 2. Slightly more advanced user - They can tweak the above by passing in config on
89 +// maxMemory, maxFD, or maxConns with Swarm.HighWater.ConnMgr.
90 +// 3. Power user - They specify all the limits they want set via Swarm.ResourceMgr.Limits
91 +// and we don't do any defaults/overrides. We pass that config blindly into libp2p resource manager.
92 +func createDefaultLimitConfig(cfg config.SwarmConfig) (rcmgr.LimitConfig, error) {
93 + maxMemoryDefaultString := humanize.Bytes(uint64(memory.TotalMemory()) / 8)
94 + maxMemoryString := cfg.ResourceMgr.MaxMemory.WithDefault(maxMemoryDefaultString)
95 + maxMemory, err := humanize.ParseBytes(maxMemoryString)
96 if err != nil {
92 - log.Fatal(err)
93 - }
94 - changes, err := jsonDiff([]byte(expectedDefaultLimits), defaults)
95 - if err != nil {
96 - log.Fatal(err)
97 - }
98 - if len(changes) > 0 {
99 - ok = false
100 - log.Errorf("===> OOF! go-libp2p-resource-manager changed DefaultLimits\n"+
101 - "=> changes ('test' represents the old value):\n%s\n"+
102 - "=> go-libp2p-resource-manager DefaultLimits update needs a review:\n"+
103 - "Please inspect if changes impact go-ipfs users, and update expectedDefaultLimits in rcmgr_defaults.go to remove this message",
104 - strings.Join(changes, "\n"),
105 - )
97 + return rcmgr.LimitConfig{}, err
98 }
99
108 - // Check 2: did go-libp2p's SetDefaultServiceLimits change?
109 - // We compare the baseline (min specs), and check if we went down in any limits.
110 - l := rcmgr.DefaultLimits
111 - libp2p.SetDefaultServiceLimits(&l)
112 - limits := l.AutoScale()
113 - testLimiter := rcmgr.NewFixedLimiter(limits)
114 -
115 - serviceDefaults, err := json.Marshal(testLimiter)
116 - if err != nil {
117 - log.Fatal(err)
118 - }
119 - changes, err = jsonDiff([]byte(expectedDefaultServiceLimits), serviceDefaults)
120 - if err != nil {
121 - log.Fatal(err)
100 + numFD := cfg.ResourceMgr.MaxFileDescriptors.WithDefault(int64(fd.GetNumFDs()) / 2)
101 +
102 + scalingLimitConfig := rcmgr.ScalingLimitConfig{
103 + SystemBaseLimit: rcmgr.BaseLimit{
104 + Memory: int64(maxMemory),
105 + FD: int(numFD),
106 +
107 + // By default, we just limit connections on the inbound side.
108 + // Note that the limit gets adjusted below if "cfg.ConnMgr.HighWater" is set.
109 + Conns: bigEnough,
110 + ConnsInbound: rcmgr.DefaultLimits.SystemBaseLimit.ConnsInbound, // same as libp2p default
111 + ConnsOutbound: bigEnough,
112 +
113 + // We limit streams since they not only take up memory and CPU.
114 + // The Memory limit protects us on the memory side,
115 + // but a StreamsInbound limit helps protect against unbound CPU consumption from stream processing.
116 + Streams: bigEnough,
117 + StreamsInbound: rcmgr.DefaultLimits.SystemBaseLimit.StreamsInbound,
118 + StreamsOutbound: bigEnough,
119 + },
120 + // Most limits don't see an increase because they're already infinite/bigEnough or at their max value.
121 + // The values that should scale based on the amount of memory allocated to libp2p need to increase accordingly.
122 + SystemLimitIncrease: rcmgr.BaseLimitIncrease{
123 + Memory: rcmgr.DefaultLimits.SystemLimitIncrease.Memory,
124 + FDFraction: rcmgr.DefaultLimits.SystemLimitIncrease.FDFraction,
125 +
126 + Conns: 0,
127 + ConnsInbound: rcmgr.DefaultLimits.SystemLimitIncrease.ConnsInbound,
128 + ConnsOutbound: 0,
129 +
130 + Streams: 0,
131 + StreamsInbound: rcmgr.DefaultLimits.SystemLimitIncrease.StreamsInbound,
132 + StreamsOutbound: 0,
133 + },
134 +
135 + // Just go with what libp2p does
136 + TransientBaseLimit: rcmgr.DefaultLimits.TransientBaseLimit,
137 + TransientLimitIncrease: rcmgr.DefaultLimits.TransientLimitIncrease,
138 +
139 + // Lets get out of the way of the allow list functionality.
140 + // If someone specified "Swarm.ResourceMgr.Allowlist" we should let it go through.
141 + AllowlistedSystemBaseLimit: infiniteBaseLimit,
142 + AllowlistedSystemLimitIncrease: noLimitIncrease,
143 +
144 + AllowlistedTransientBaseLimit: infiniteBaseLimit,
145 + AllowlistedTransientLimitIncrease: noLimitIncrease,
146 +
147 + // Keep it simple by not having Service, ServicePeer, Protocol, ProtocolPeer, Conn, or Stream limits.
148 + ServiceBaseLimit: infiniteBaseLimit,
149 + ServiceLimitIncrease: noLimitIncrease,
150 +
151 + ServicePeerBaseLimit: infiniteBaseLimit,
152 + ServicePeerLimitIncrease: noLimitIncrease,
153 +
154 + ProtocolBaseLimit: infiniteBaseLimit,
155 + ProtocolLimitIncrease: noLimitIncrease,
156 +
157 + ProtocolPeerBaseLimit: infiniteBaseLimit,
158 + ProtocolPeerLimitIncrease: noLimitIncrease,
159 +
160 + ConnBaseLimit: infiniteBaseLimit,
161 + ConnLimitIncrease: noLimitIncrease,
162 +
163 + StreamBaseLimit: infiniteBaseLimit,
164 + StreamLimitIncrease: noLimitIncrease,
165 +
166 + // Limit the resources consumed by a peer.
167 + // This doesn't protect us against intentional DoS attacks since an attacker can easily spin up multiple peers.
168 + // We specify this limit against unintentional DoS attacks (e.g., a peer has a bug and is sending too much traffic intentionally).
169 + // In that case we want to keep that peer's resource consumption contained.
170 + // To keep this simple, we only constrain inbound connections and streams.
171 + PeerBaseLimit: rcmgr.BaseLimit{
172 + Memory: bigEnough,
173 + FD: bigEnough,
174 + Conns: bigEnough,
175 + ConnsInbound: rcmgr.DefaultLimits.PeerBaseLimit.ConnsInbound,
176 + ConnsOutbound: bigEnough,
177 + Streams: bigEnough,
178 + StreamsInbound: rcmgr.DefaultLimits.PeerBaseLimit.StreamsInbound,
179 + StreamsOutbound: bigEnough,
180 + },
181 + // Most limits don't see an increase because they're already infinite/bigEnough.
182 + // The values that should scale based on the amount of memory allocated to libp2p need to increase accordingly.
183 + PeerLimitIncrease: rcmgr.BaseLimitIncrease{
184 + Memory: 0,
185 + FDFraction: 0,
186 + Conns: 0,
187 + ConnsInbound: rcmgr.DefaultLimits.PeerLimitIncrease.ConnsInbound,
188 + ConnsOutbound: 0,
189 + Streams: 0,
190 + StreamsInbound: rcmgr.DefaultLimits.PeerLimitIncrease.StreamsInbound,
191 + StreamsOutbound: 0,
192 + },
193 }
123 - if len(changes) > 0 {
124 - oldState := map[string]int{}
125 - type Op struct {
126 - Op string
127 - Path string
128 - Value int
129 - }
130 - for _, changeStr := range changes {
131 - change := Op{}
132 - err := json.Unmarshal([]byte(changeStr), &change)
133 - if err != nil {
134 - continue
135 - }
136 - if change.Op == "test" {
137 - oldState[change.Path] = change.Value
138 - }
139 - }
194
141 - for _, changeStr := range changes {
142 - change := Op{}
143 - err := json.Unmarshal([]byte(changeStr), &change)
144 - if err != nil {
145 - continue
146 - }
147 - if change.Op == "replace" {
148 - oldVal, okFound := oldState[change.Path]
149 - if okFound && oldVal > change.Value {
150 - ok = false
151 - fmt.Printf("reduced value for %s. Old: %v; new: %v\n", change.Path, oldVal, change.Value)
152 - }
153 - }
154 - }
195 + // Whatever limits libp2p has specifically tuned for its protocols/services we'll apply.
196 + libp2p.SetDefaultServiceLimits(&scalingLimitConfig)
197
156 - if !ok {
157 - log.Errorf("===> OOF! go-libp2p changed DefaultServiceLimits\n" +
158 - "=> See the aboce reduced values for info.\n" +
159 - "=> go-libp2p SetDefaultServiceLimits update needs a review:\n" +
160 - "Please inspect if changes impact go-ipfs users, and update expectedDefaultServiceLimits in rcmgr_defaults.go to remove this message",
161 - )
162 - }
163 - }
164 - if !ok {
165 - log.Fatal("daemon will refuse to run with the resource manager until this is resolved")
166 - }
167 -}
198 + defaultLimitConfig := scalingLimitConfig.Scale(int64(maxMemory), int(numFD))
199
169 -// jsonDiff compares two strings and returns diff in JSON Patch format
170 -func jsonDiff(old []byte, updated []byte) ([]string, error) {
171 - // generate 'invertible' patch which includes old values as "test" op
172 - patch, err := jsondiff.CompareJSONOpts(old, updated, jsondiff.Invertible())
173 - changes := make([]string, len(patch))
174 - if err != nil {
175 - return changes, err
176 - }
177 - for i, op := range patch {
178 - changes[i] = fmt.Sprintf(" %s", op)
200 + // If a high water mark is set:
201 + if cfg.ConnMgr.Type == "basic" {
202 + // set the connection limit higher than high water mark so that the ConnMgr has "space and time" to close "least useful" connections.
203 + defaultLimitConfig.System.Conns = 2 * cfg.ConnMgr.HighWater
204 + log.Info("adjusted default resource manager System.Conns limits to match ConnMgr.HighWater value of %s", cfg.ConnMgr.HighWater)
205 }
180 - return changes, nil
181 -}
206
183 -// https://github.com/libp2p/go-libp2p/blob/v0.22.0/p2p/host/resource-manager/limit_defaults.go#L343
184 -const expectedDefaultLimits = `{
185 - "SystemBaseLimit": {
186 - "Streams": 2048,
187 - "StreamsInbound": 1024,
188 - "StreamsOutbound": 2048,
189 - "Conns": 128,
190 - "ConnsInbound": 64,
191 - "ConnsOutbound": 128,
192 - "FD": 256,
193 - "Memory": 134217728
194 - },
195 - "SystemLimitIncrease": {
196 - "Streams": 2048,
197 - "StreamsInbound": 1024,
198 - "StreamsOutbound": 2048,
199 - "Conns": 128,
200 - "ConnsInbound": 64,
201 - "ConnsOutbound": 128,
202 - "Memory": 1073741824,
203 - "FDFraction": 1
204 - },
205 - "TransientBaseLimit": {
206 - "Streams": 256,
207 - "StreamsInbound": 128,
208 - "StreamsOutbound": 256,
209 - "Conns": 64,
210 - "ConnsInbound": 32,
211 - "ConnsOutbound": 64,
212 - "FD": 64,
213 - "Memory": 33554432
214 - },
215 - "TransientLimitIncrease": {
216 - "Streams": 256,
217 - "StreamsInbound": 128,
218 - "StreamsOutbound": 256,
219 - "Conns": 32,
220 - "ConnsInbound": 16,
221 - "ConnsOutbound": 32,
222 - "Memory": 134217728,
223 - "FDFraction": 0.25
224 - },
225 - "AllowlistedSystemBaseLimit": {
226 - "Streams": 2048,
227 - "StreamsInbound": 1024,
228 - "StreamsOutbound": 2048,
229 - "Conns": 128,
230 - "ConnsInbound": 64,
231 - "ConnsOutbound": 128,
232 - "FD": 256,
233 - "Memory": 134217728
234 - },
235 - "AllowlistedSystemLimitIncrease": {
236 - "Streams": 2048,
237 - "StreamsInbound": 1024,
238 - "StreamsOutbound": 2048,
239 - "Conns": 128,
240 - "ConnsInbound": 64,
241 - "ConnsOutbound": 128,
242 - "Memory": 1073741824,
243 - "FDFraction": 1
244 - },
245 - "AllowlistedTransientBaseLimit": {
246 - "Streams": 256,
247 - "StreamsInbound": 128,
248 - "StreamsOutbound": 256,
249 - "Conns": 64,
250 - "ConnsInbound": 32,
251 - "ConnsOutbound": 64,
252 - "FD": 64,
253 - "Memory": 33554432
254 - },
255 - "AllowlistedTransientLimitIncrease": {
256 - "Streams": 256,
257 - "StreamsInbound": 128,
258 - "StreamsOutbound": 256,
259 - "Conns": 32,
260 - "ConnsInbound": 16,
261 - "ConnsOutbound": 32,
262 - "Memory": 134217728,
263 - "FDFraction": 0.25
264 - },
265 - "ServiceBaseLimit": {
266 - "Streams": 4096,
267 - "StreamsInbound": 1024,
268 - "StreamsOutbound": 4096,
269 - "Conns": 0,
270 - "ConnsInbound": 0,
271 - "ConnsOutbound": 0,
272 - "FD": 0,
273 - "Memory": 67108864
274 - },
275 - "ServiceLimitIncrease": {
276 - "Streams": 2048,
277 - "StreamsInbound": 512,
278 - "StreamsOutbound": 2048,
279 - "Conns": 0,
280 - "ConnsInbound": 0,
281 - "ConnsOutbound": 0,
282 - "Memory": 134217728,
283 - "FDFraction": 0
284 - },
285 - "ServiceLimits": null,
286 - "ServicePeerBaseLimit": {
287 - "Streams": 256,
288 - "StreamsInbound": 128,
289 - "StreamsOutbound": 256,
290 - "Conns": 0,
291 - "ConnsInbound": 0,
292 - "ConnsOutbound": 0,
293 - "FD": 0,
294 - "Memory": 16777216
295 - },
296 - "ServicePeerLimitIncrease": {
297 - "Streams": 8,
298 - "StreamsInbound": 4,
299 - "StreamsOutbound": 8,
300 - "Conns": 0,
301 - "ConnsInbound": 0,
302 - "ConnsOutbound": 0,
303 - "Memory": 4194304,
304 - "FDFraction": 0
305 - },
306 - "ServicePeerLimits": null,
307 - "ProtocolBaseLimit": {
308 - "Streams": 2048,
309 - "StreamsInbound": 512,
310 - "StreamsOutbound": 2048,
311 - "Conns": 0,
312 - "ConnsInbound": 0,
313 - "ConnsOutbound": 0,
314 - "FD": 0,
315 - "Memory": 67108864
316 - },
317 - "ProtocolLimitIncrease": {
318 - "Streams": 512,
319 - "StreamsInbound": 256,
320 - "StreamsOutbound": 512,
321 - "Conns": 0,
322 - "ConnsInbound": 0,
323 - "ConnsOutbound": 0,
324 - "Memory": 171966464,
325 - "FDFraction": 0
326 - },
327 - "ProtocolLimits": null,
328 - "ProtocolPeerBaseLimit": {
329 - "Streams": 256,
330 - "StreamsInbound": 64,
331 - "StreamsOutbound": 128,
332 - "Conns": 0,
333 - "ConnsInbound": 0,
334 - "ConnsOutbound": 0,
335 - "FD": 0,
336 - "Memory": 16777216
337 - },
338 - "ProtocolPeerLimitIncrease": {
339 - "Streams": 16,
340 - "StreamsInbound": 4,
341 - "StreamsOutbound": 8,
342 - "Conns": 0,
343 - "ConnsInbound": 0,
344 - "ConnsOutbound": 0,
345 - "Memory": 4,
346 - "FDFraction": 0
347 - },
348 - "ProtocolPeerLimits": null,
349 - "PeerBaseLimit": {
350 - "Streams": 512,
351 - "StreamsInbound": 256,
352 - "StreamsOutbound": 512,
353 - "Conns": 8,
354 - "ConnsInbound": 4,
355 - "ConnsOutbound": 8,
356 - "FD": 4,
357 - "Memory": 67108864
358 - },
359 - "PeerLimitIncrease": {
360 - "Streams": 256,
361 - "StreamsInbound": 128,
362 - "StreamsOutbound": 256,
363 - "Conns": 0,
364 - "ConnsInbound": 0,
365 - "ConnsOutbound": 0,
366 - "Memory": 134217728,
367 - "FDFraction": 0.015625
368 - },
369 - "PeerLimits": null,
370 - "ConnBaseLimit": {
371 - "Streams": 0,
372 - "StreamsInbound": 0,
373 - "StreamsOutbound": 0,
374 - "Conns": 1,
375 - "ConnsInbound": 1,
376 - "ConnsOutbound": 1,
377 - "FD": 1,
378 - "Memory": 33554432
379 - },
380 - "ConnLimitIncrease": {
381 - "Streams": 0,
382 - "StreamsInbound": 0,
383 - "StreamsOutbound": 0,
384 - "Conns": 0,
385 - "ConnsInbound": 0,
386 - "ConnsOutbound": 0,
387 - "Memory": 0,
388 - "FDFraction": 0
389 - },
390 - "StreamBaseLimit": {
391 - "Streams": 1,
392 - "StreamsInbound": 1,
393 - "StreamsOutbound": 1,
394 - "Conns": 0,
395 - "ConnsInbound": 0,
396 - "ConnsOutbound": 0,
397 - "FD": 0,
398 - "Memory": 16777216
399 - },
400 - "StreamLimitIncrease": {
401 - "Streams": 0,
402 - "StreamsInbound": 0,
403 - "StreamsOutbound": 0,
404 - "Conns": 0,
405 - "ConnsInbound": 0,
406 - "ConnsOutbound": 0,
407 - "Memory": 0,
408 - "FDFraction": 0
409 - }
410 -}`
411 -
412 -// Generated from the default limits and scaling to 0 (base limit).
413 -const expectedDefaultServiceLimits = `{
414 - "System": {
415 - "Streams": 2048,
416 - "StreamsInbound": 1024,
417 - "StreamsOutbound": 2048,
418 - "Conns": 128,
419 - "ConnsInbound": 64,
420 - "ConnsOutbound": 128,
421 - "FD": 256,
422 - "Memory": 134217728
423 - },
424 - "Transient": {
425 - "Streams": 256,
426 - "StreamsInbound": 128,
427 - "StreamsOutbound": 256,
428 - "Conns": 64,
429 - "ConnsInbound": 32,
430 - "ConnsOutbound": 64,
431 - "FD": 64,
432 - "Memory": 33554432
433 - },
434 - "AllowlistedSystem": {
435 - "Streams": 2048,
436 - "StreamsInbound": 1024,
437 - "StreamsOutbound": 2048,
438 - "Conns": 128,
439 - "ConnsInbound": 64,
440 - "ConnsOutbound": 128,
441 - "FD": 256,
442 - "Memory": 134217728
443 - },
444 - "AllowlistedTransient": {
445 - "Streams": 256,
446 - "StreamsInbound": 128,
447 - "StreamsOutbound": 256,
448 - "Conns": 64,
449 - "ConnsInbound": 32,
450 - "ConnsOutbound": 64,
451 - "FD": 64,
452 - "Memory": 33554432
453 - },
454 - "ServiceDefault": {
455 - "Streams": 4096,
456 - "StreamsInbound": 1024,
457 - "StreamsOutbound": 4096,
458 - "Conns": 0,
459 - "ConnsInbound": 0,
460 - "ConnsOutbound": 0,
461 - "FD": 0,
462 - "Memory": 67108864
463 - },
464 - "Service": {
465 - "libp2p.autonat": {
466 - "Streams": 64,
467 - "StreamsInbound": 64,
468 - "StreamsOutbound": 64,
469 - "Conns": 0,
470 - "ConnsInbound": 0,
471 - "ConnsOutbound": 0,
472 - "FD": 0,
473 - "Memory": 4194304
474 - },
475 - "libp2p.holepunch": {
476 - "Streams": 64,
477 - "StreamsInbound": 32,
478 - "StreamsOutbound": 32,
479 - "Conns": 0,
480 - "ConnsInbound": 0,
481 - "ConnsOutbound": 0,
482 - "FD": 0,
483 - "Memory": 4194304
484 - },
485 - "libp2p.identify": {
486 - "Streams": 128,
487 - "StreamsInbound": 64,
488 - "StreamsOutbound": 64,
489 - "Conns": 0,
490 - "ConnsInbound": 0,
491 - "ConnsOutbound": 0,
492 - "FD": 0,
493 - "Memory": 4194304
494 - },
495 - "libp2p.ping": {
496 - "Streams": 64,
497 - "StreamsInbound": 64,
498 - "StreamsOutbound": 64,
499 - "Conns": 0,
500 - "ConnsInbound": 0,
501 - "ConnsOutbound": 0,
502 - "FD": 0,
503 - "Memory": 4194304
504 - },
505 - "libp2p.relay/v1": {
506 - "Streams": 256,
507 - "StreamsInbound": 256,
508 - "StreamsOutbound": 256,
509 - "Conns": 0,
510 - "ConnsInbound": 0,
511 - "ConnsOutbound": 0,
512 - "FD": 0,
513 - "Memory": 16777216
514 - },
515 - "libp2p.relay/v2": {
516 - "Streams": 256,
517 - "StreamsInbound": 256,
518 - "StreamsOutbound": 256,
519 - "Conns": 0,
520 - "ConnsInbound": 0,
521 - "ConnsOutbound": 0,
522 - "FD": 0,
523 - "Memory": 16777216
524 - }
525 - },
526 - "ServicePeerDefault": {
527 - "Streams": 256,
528 - "StreamsInbound": 128,
529 - "StreamsOutbound": 256,
530 - "Conns": 0,
531 - "ConnsInbound": 0,
532 - "ConnsOutbound": 0,
533 - "FD": 0,
534 - "Memory": 16777216
535 - },
536 - "ServicePeer": {
537 - "libp2p.autonat": {
538 - "Streams": 2,
539 - "StreamsInbound": 2,
540 - "StreamsOutbound": 2,
541 - "Conns": 0,
542 - "ConnsInbound": 0,
543 - "ConnsOutbound": 0,
544 - "FD": 0,
545 - "Memory": 1048576
546 - },
547 - "libp2p.holepunch": {
548 - "Streams": 2,
549 - "StreamsInbound": 2,
550 - "StreamsOutbound": 2,
551 - "Conns": 0,
552 - "ConnsInbound": 0,
553 - "ConnsOutbound": 0,
554 - "FD": 0,
555 - "Memory": 1048576
556 - },
557 - "libp2p.identify": {
558 - "Streams": 32,
559 - "StreamsInbound": 16,
560 - "StreamsOutbound": 16,
561 - "Conns": 0,
562 - "ConnsInbound": 0,
563 - "ConnsOutbound": 0,
564 - "FD": 0,
565 - "Memory": 1048576
566 - },
567 - "libp2p.ping": {
568 - "Streams": 4,
569 - "StreamsInbound": 2,
570 - "StreamsOutbound": 3,
571 - "Conns": 0,
572 - "ConnsInbound": 0,
573 - "ConnsOutbound": 0,
574 - "FD": 0,
575 - "Memory": 8590458880
576 - },
577 - "libp2p.relay/v1": {
578 - "Streams": 64,
579 - "StreamsInbound": 64,
580 - "StreamsOutbound": 64,
581 - "Conns": 0,
582 - "ConnsInbound": 0,
583 - "ConnsOutbound": 0,
584 - "FD": 0,
585 - "Memory": 1048576
586 - },
587 - "libp2p.relay/v2": {
588 - "Streams": 64,
589 - "StreamsInbound": 64,
590 - "StreamsOutbound": 64,
591 - "Conns": 0,
592 - "ConnsInbound": 0,
593 - "ConnsOutbound": 0,
594 - "FD": 0,
595 - "Memory": 1048576
596 - }
597 - },
598 - "ProtocolDefault": {
599 - "Streams": 2048,
600 - "StreamsInbound": 512,
601 - "StreamsOutbound": 2048,
602 - "Conns": 0,
603 - "ConnsInbound": 0,
604 - "ConnsOutbound": 0,
605 - "FD": 0,
606 - "Memory": 67108864
607 - },
608 - "Protocol": {
609 - "/ipfs/id/1.0.0": {
610 - "Streams": 128,
611 - "StreamsInbound": 64,
612 - "StreamsOutbound": 64,
613 - "Conns": 0,
614 - "ConnsInbound": 0,
615 - "ConnsOutbound": 0,
616 - "FD": 0,
617 - "Memory": 4194304
618 - },
619 - "/ipfs/id/push/1.0.0": {
620 - "Streams": 128,
621 - "StreamsInbound": 64,
622 - "StreamsOutbound": 64,
623 - "Conns": 0,
624 - "ConnsInbound": 0,
625 - "ConnsOutbound": 0,
626 - "FD": 0,
627 - "Memory": 4194304
628 - },
629 - "/ipfs/ping/1.0.0": {
630 - "Streams": 64,
631 - "StreamsInbound": 64,
632 - "StreamsOutbound": 64,
633 - "Conns": 0,
634 - "ConnsInbound": 0,
635 - "ConnsOutbound": 0,
636 - "FD": 0,
637 - "Memory": 4194304
638 - },
639 - "/libp2p/autonat/1.0.0": {
640 - "Streams": 64,
641 - "StreamsInbound": 64,
642 - "StreamsOutbound": 64,
643 - "Conns": 0,
644 - "ConnsInbound": 0,
645 - "ConnsOutbound": 0,
646 - "FD": 0,
647 - "Memory": 4194304
648 - },
649 - "/libp2p/circuit/relay/0.1.0": {
650 - "Streams": 640,
651 - "StreamsInbound": 640,
652 - "StreamsOutbound": 640,
653 - "Conns": 0,
654 - "ConnsInbound": 0,
655 - "ConnsOutbound": 0,
656 - "FD": 0,
657 - "Memory": 16777216
658 - },
659 - "/libp2p/circuit/relay/0.2.0/hop": {
660 - "Streams": 640,
661 - "StreamsInbound": 640,
662 - "StreamsOutbound": 640,
663 - "Conns": 0,
664 - "ConnsInbound": 0,
665 - "ConnsOutbound": 0,
666 - "FD": 0,
667 - "Memory": 16777216
668 - },
669 - "/libp2p/circuit/relay/0.2.0/stop": {
670 - "Streams": 640,
671 - "StreamsInbound": 640,
672 - "StreamsOutbound": 640,
673 - "Conns": 0,
674 - "ConnsInbound": 0,
675 - "ConnsOutbound": 0,
676 - "FD": 0,
677 - "Memory": 16777216
678 - },
679 - "/libp2p/dcutr": {
680 - "Streams": 64,
681 - "StreamsInbound": 32,
682 - "StreamsOutbound": 32,
683 - "Conns": 0,
684 - "ConnsInbound": 0,
685 - "ConnsOutbound": 0,
686 - "FD": 0,
687 - "Memory": 4194304
688 - },
689 - "/p2p/id/delta/1.0.0": {
690 - "Streams": 128,
691 - "StreamsInbound": 64,
692 - "StreamsOutbound": 64,
693 - "Conns": 0,
694 - "ConnsInbound": 0,
695 - "ConnsOutbound": 0,
696 - "FD": 0,
697 - "Memory": 4194304
698 - }
699 - },
700 - "ProtocolPeerDefault": {
701 - "Streams": 256,
702 - "StreamsInbound": 64,
703 - "StreamsOutbound": 128,
704 - "Conns": 0,
705 - "ConnsInbound": 0,
706 - "ConnsOutbound": 0,
707 - "FD": 0,
708 - "Memory": 16777216
709 - },
710 - "ProtocolPeer": {
711 - "/ipfs/id/1.0.0": {
712 - "Streams": 32,
713 - "StreamsInbound": 16,
714 - "StreamsOutbound": 16,
715 - "Conns": 0,
716 - "ConnsInbound": 0,
717 - "ConnsOutbound": 0,
718 - "FD": 0,
719 - "Memory": 8590458880
720 - },
721 - "/ipfs/id/push/1.0.0": {
722 - "Streams": 32,
723 - "StreamsInbound": 16,
724 - "StreamsOutbound": 16,
725 - "Conns": 0,
726 - "ConnsInbound": 0,
727 - "ConnsOutbound": 0,
728 - "FD": 0,
729 - "Memory": 8590458880
730 - },
731 - "/ipfs/ping/1.0.0": {
732 - "Streams": 4,
733 - "StreamsInbound": 2,
734 - "StreamsOutbound": 3,
735 - "Conns": 0,
736 - "ConnsInbound": 0,
737 - "ConnsOutbound": 0,
738 - "FD": 0,
739 - "Memory": 8590458880
740 - },
741 - "/libp2p/autonat/1.0.0": {
742 - "Streams": 2,
743 - "StreamsInbound": 2,
744 - "StreamsOutbound": 2,
745 - "Conns": 0,
746 - "ConnsInbound": 0,
747 - "ConnsOutbound": 0,
748 - "FD": 0,
749 - "Memory": 1048576
750 - },
751 - "/libp2p/circuit/relay/0.1.0": {
752 - "Streams": 128,
753 - "StreamsInbound": 128,
754 - "StreamsOutbound": 128,
755 - "Conns": 0,
756 - "ConnsInbound": 0,
757 - "ConnsOutbound": 0,
758 - "FD": 0,
759 - "Memory": 33554432
760 - },
761 - "/libp2p/circuit/relay/0.2.0/hop": {
762 - "Streams": 128,
763 - "StreamsInbound": 128,
764 - "StreamsOutbound": 128,
765 - "Conns": 0,
766 - "ConnsInbound": 0,
767 - "ConnsOutbound": 0,
768 - "FD": 0,
769 - "Memory": 33554432
770 - },
771 - "/libp2p/circuit/relay/0.2.0/stop": {
772 - "Streams": 128,
773 - "StreamsInbound": 128,
774 - "StreamsOutbound": 128,
775 - "Conns": 0,
776 - "ConnsInbound": 0,
777 - "ConnsOutbound": 0,
778 - "FD": 0,
779 - "Memory": 33554432
780 - },
781 - "/libp2p/dcutr": {
782 - "Streams": 2,
783 - "StreamsInbound": 2,
784 - "StreamsOutbound": 2,
785 - "Conns": 0,
786 - "ConnsInbound": 0,
787 - "ConnsOutbound": 0,
788 - "FD": 0,
789 - "Memory": 1048576
790 - },
791 - "/p2p/id/delta/1.0.0": {
792 - "Streams": 32,
793 - "StreamsInbound": 16,
794 - "StreamsOutbound": 16,
795 - "Conns": 0,
796 - "ConnsInbound": 0,
797 - "ConnsOutbound": 0,
798 - "FD": 0,
799 - "Memory": 8590458880
800 - }
801 - },
802 - "PeerDefault": {
803 - "Streams": 512,
804 - "StreamsInbound": 256,
805 - "StreamsOutbound": 512,
806 - "Conns": 8,
807 - "ConnsInbound": 4,
808 - "ConnsOutbound": 8,
809 - "FD": 4,
810 - "Memory": 67108864
811 - },
812 - "Conn": {
813 - "Streams": 0,
814 - "StreamsInbound": 0,
815 - "StreamsOutbound": 0,
816 - "Conns": 1,
817 - "ConnsInbound": 1,
818 - "ConnsOutbound": 1,
819 - "FD": 1,
820 - "Memory": 1048576
821 - },
822 - "Stream": {
823 - "Streams": 1,
824 - "StreamsInbound": 1,
825 - "StreamsOutbound": 1,
826 - "Conns": 0,
827 - "ConnsInbound": 0,
828 - "ConnsOutbound": 0,
829 - "FD": 0,
830 - "Memory": 16777216
831 - }
832 -}`
207 + return defaultLimitConfig, nil
208 +}
core/node/libp2p/rcmgr_logging.go
+21 -6
@@ -22,7 +22,7 @@ type loggingResourceManager struct {
22 logInterval time.Duration
23
24 mut sync.Mutex
25 - limitExceededErrs uint64
25 + limitExceededErrs map[string]int
26 }
27
28 type loggingScope struct {
@@ -47,11 +47,17 @@ func (n *loggingResourceManager) start(ctx context.Context) {
47 case <-ticker.C:
48 n.mut.Lock()
49 errs := n.limitExceededErrs
50 - n.limitExceededErrs = 0
51 - n.mut.Unlock()
52 - if errs != 0 {
53 - n.logger.Warnf("Resource limits were exceeded %d times, consider inspecting logs and raising the resource manager limits.", errs)
50 + n.limitExceededErrs = make(map[string]int)
51 +
52 + for e, count := range errs {
53 + n.logger.Errorf("Resource limits were exceeded %d times with error %q.", count, e)
54 }
55 +
56 + if len(errs) != 0 {
57 + n.logger.Errorf("Consider inspecting logs and raising the resource manager limits. Documentation: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgr")
58 + }
59 +
60 + n.mut.Unlock()
61 case <-ctx.Done():
62 return
63 }
@@ -62,7 +68,16 @@ func (n *loggingResourceManager) start(ctx context.Context) {
68 func (n *loggingResourceManager) countErrs(err error) {
69 if errors.Is(err, network.ErrResourceLimitExceeded) {
70 n.mut.Lock()
65 - n.limitExceededErrs++
71 + if n.limitExceededErrs == nil {
72 + n.limitExceededErrs = make(map[string]int)
73 + }
74 +
75 + // we need to unwrap the error to get the limit scope and the kind of reached limit
76 + eout := errors.Unwrap(err)
77 + if eout != nil {
78 + n.limitExceededErrs[eout.Error()]++
79 + }
80 +
81 n.mut.Unlock()
82 }
83 }
core/node/libp2p/rcmgr_logging_test.go
+1 -1
@@ -55,7 +55,7 @@ func TestLoggingResourceManager(t *testing.T) {
55 if oLogs.Len() == 0 {
56 continue
57 }
58 - require.Equal(t, "Resource limits were exceeded 2 times, consider inspecting logs and raising the resource manager limits.", oLogs.All()[0].Message)
58 + require.Equal(t, "Resource limits were exceeded 2 times with error \"system: cannot reserve inbound connection: resource limit exceeded\".", oLogs.All()[0].Message)
59 return
60 }
61 }
docs/config.md
+22 -13
@@ -141,6 +141,8 @@ config file at runtime.
141 - [`Swarm.ConnMgr.GracePeriod`](#swarmconnmgrgraceperiod)
142 - [`Swarm.ResourceMgr`](#swarmresourcemgr)
143 - [`Swarm.ResourceMgr.Enabled`](#swarmresourcemgrenabled)
144 + - [`Swarm.ResourceMgr.MaxMemory`](#swarmresourcemgrmaxmemory)
145 + - [`Swarm.ResourceMgr.MaxFileDescriptors`](#swarmresourcemgrmaxfiledescriptors)
146 - [`Swarm.ResourceMgr.Limits`](#swarmresourcemgrlimits)
147 - [`Swarm.ResourceMgr.Allowlist`](#swarmresourcemgrallowlist)
148 - [`Swarm.Transports`](#swarmtransports)
@@ -1800,35 +1802,42 @@ Type: `duration`
1802
1803 ### `Swarm.ResourceMgr`
1804
1803 -**EXPERIMENTAL: `Swarm.ResourceMgr` configuration will change in future release**
1804 -
1805 The [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) allows setting limits per a scope,
1806 and tracking recource usage over time.
1807
1808 #### `Swarm.ResourceMgr.Enabled`
1809
1810 -**EXPERIMENTAL: `Swarm.ResourceMgr` is in active development, enable it only if you want to provide maintainers with feedback**
1811 -
1812 -
1810 Enables the libp2p Network Resource Manager and auguments the default limits
1811 using user-defined ones in `Swarm.ResourceMgr.Limits` (if present).
1812
1813 Various `*rcmgr_*` metrics can be accessed as the prometheus endpoint at `{Addresses.API}/debug/metrics/prometheus` (default: `http://127.0.0.1:5001/debug/metrics/prometheus`)
1814
1818 -Default: `false`
1815 +Default: `true`
1816
1817 Type: `flag`
1818
1822 -#### `Swarm.ResourceMgr.Limits`
1819 +#### `Swarm.ResourceMgr.MaxMemory`
1820 +
1821 +The maximum amount of memory that the libp2p resource manager will allow.
1822
1824 -**EXPERIMENTAL: `Swarm.ResourceMgr.Limits` configuration will change in future release, exposed here only for convenience**
1823 +Default: `[TOTAL_SYSTEM_MEMORY]/8`
1824 +Type: `optionalBytes`
1825
1826 -Map of resource limits [per scope](https://github.com/libp2p/go-libp2p-resource-manager#resource-scopes).
1826 +#### `Swarm.ResourceMgr.MaxFileDescriptors`
1827 +
1828 +Define the maximum number of file descriptors that libp2p can use.
1829 +
1830 +This param is ignored on Windows.
1831 +
1832 +Default `[TOTAL_SYSTEM_FILE_DESCRIPTORS]/2`
1833 +Type: `optionalInteger`
1834 +
1835 +#### `Swarm.ResourceMgr.Limits`
1836
1828 -The map supports fields from [`BasicLimiterConfig`](https://github.com/libp2p/go-libp2p-resource-manager/blob/v0.3.0/limit_config.go#L165-L185)
1829 -struct from [go-libp2p-resource-manager](https://github.com/libp2p/go-libp2p-resource-manager#readme).
1837 +Map of resource limits [per scope](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#resource-scopes).
1838
1831 -**Example: (format may change in future release)**
1839 +The map supports fields from [`ScalingLimitConfig`](https://github.com/libp2p/go-libp2p/blob/master/p2p/host/resource-manager/limit_defaults.go#L21-L59)
1840 +struct from [go-libp2p-resource-manager](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#readme).
1841
1842 ```json
1843 {
@@ -1865,7 +1874,7 @@ Type: `object[string->object]`
1874 #### `Swarm.ResourceMgr.Allowlist`
1875
1876 A list of multiaddrs that can bypass normal system limits (but are still limited by the allowlist scope).
1868 -Convenience config around [go-libp2p-resource-manager#Allowlist.Add](https://pkg.go.dev/github.com/libp2p/go-libp2p-resource-manager#Allowlist.Add).
1877 +Convenience config around [go-libp2p-resource-manager#Allowlist.Add](https://pkg.go.dev/github.com/libp2p/go-libp2p/p2p/host/resource-manager#Allowlist.Add).
1878
1879 Default: `[]`
1880
docs/examples/kubo-as-a-library/go.mod
-4
@@ -178,10 +178,6 @@ require (
178 github.com/spaolacci/murmur3 v1.1.0 // indirect
179 github.com/stretchr/objx v0.4.0 // indirect
180 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
181 - github.com/tidwall/gjson v1.14.0 // indirect
182 - github.com/tidwall/match v1.1.1 // indirect
183 - github.com/tidwall/pretty v1.2.0 // indirect
184 - github.com/wI2L/jsondiff v0.2.0 // indirect
181 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
182 github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect
183 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
docs/examples/kubo-as-a-library/go.sum
-8
@@ -1533,12 +1533,6 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70
1533 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
1534 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
1535 github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
1536 -github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
1537 -github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
1538 -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
1539 -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
1540 -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
1541 -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
1536 github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
1537 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
1538 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
@@ -1552,8 +1546,6 @@ github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2
1546 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
1547 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
1548 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
1555 -github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k=
1556 -github.com/wI2L/jsondiff v0.2.0/go.mod h1:axTcwtBkY4TsKuV+RgoMhHyHKKFRI6nnjRLi8LLYQnA=
1549 github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
1550 github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
1551 github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
go.mod
+1 -5
@@ -90,11 +90,11 @@ require (
90 github.com/multiformats/go-multicodec v0.7.0
91 github.com/multiformats/go-multihash v0.2.1
92 github.com/opentracing/opentracing-go v1.2.0
93 + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
94 github.com/pkg/errors v0.9.1
95 github.com/prometheus/client_golang v1.13.0
96 github.com/stretchr/testify v1.8.0
97 github.com/syndtr/goleveldb v1.0.0
97 - github.com/wI2L/jsondiff v0.2.0
98 github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1
99 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
100 go.opencensus.io v0.23.0
@@ -210,7 +210,6 @@ require (
210 github.com/onsi/ginkgo v1.16.5 // indirect
211 github.com/opencontainers/runtime-spec v1.0.2 // indirect
212 github.com/openzipkin/zipkin-go v0.4.0 // indirect
213 - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
213 github.com/pmezard/go-difflib v1.0.0 // indirect
214 github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
215 github.com/prometheus/client_model v0.2.0 // indirect
@@ -222,9 +221,6 @@ require (
221 github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
222 github.com/spaolacci/murmur3 v1.1.0 // indirect
223 github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e // indirect
225 - github.com/tidwall/gjson v1.14.0 // indirect
226 - github.com/tidwall/match v1.1.1 // indirect
227 - github.com/tidwall/pretty v1.2.0 // indirect
224 github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
225 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
226 github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect
go.sum
-8
@@ -1508,12 +1508,6 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP
1508 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
1509 github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e h1:T5PdfK/M1xyrHwynxMIVMWLS7f/qHwfslZphxtGnw7s=
1510 github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
1511 -github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
1512 -github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
1513 -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
1514 -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
1515 -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
1516 -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
1511 github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
1512 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
1513 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
@@ -1528,8 +1522,6 @@ github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2
1522 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
1523 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
1524 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
1531 -github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k=
1532 -github.com/wI2L/jsondiff v0.2.0/go.mod h1:axTcwtBkY4TsKuV+RgoMhHyHKKFRI6nnjRLi8LLYQnA=
1525 github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
1526 github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
1527 github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
test/sharness/t0119-prometheus.sh
+4
@@ -10,6 +10,10 @@ test_description="Test prometheus metrics are exposed correctly"
10
11 test_init_ipfs
12
13 +test_expect_success "enable ResourceMgr in the config" '
14 + ipfs config --json Swarm.ResourceMgr.Enabled false
15 +'
16 +
17 test_launch_ipfs_daemon
18
19 test_expect_success "collect metrics" '
test/sharness/t0139-swarm-rcmgr.sh
+12 -8
@@ -2,13 +2,15 @@
2 #
3 test_description="Test ipfs swarm ResourceMgr config and commands"
4
5 -export IPFS_CHECK_RCMGR_DEFAULTS=1
6 -
5 . lib/test-lib.sh
6
7 test_init_ipfs
8
11 -# test correct behavior when resource manager is disabled (default behavior)
9 +test_expect_success 'Disable resource manager' '
10 + ipfs config --bool Swarm.ResourceMgr.Enabled false
11 +'
12 +
13 +# test correct behavior when resource manager is disabled
14 test_launch_ipfs_daemon
15
16 test_expect_success 'Swarm limit should fail since RM is disabled' '
@@ -79,11 +81,13 @@ test_expect_success 'connected: swarm stats all working properly' '
81 test_expect_success 'ResourceMgr enabled: swarm stats' '
82 ipfs swarm stats all --enc=json | tee json &&
83 jq -e .System.Memory < json &&
82 - jq -e .System.NumConnsInbound < json &&
83 - jq -e .System.NumConnsOutbound < json &&
84 - jq -e .System.NumFD < json &&
85 - jq -e .System.NumStreamsInbound < json &&
86 - jq -e .System.NumStreamsOutbound < json &&
84 + jq -e .System.FD < json &&
85 + jq -e .System.Conns < json &&
86 + jq -e .System.ConnsInbound < json &&
87 + jq -e .System.ConnsOutbound < json &&
88 + jq -e .System.Streams < json &&
89 + jq -e .System.StreamsInbound < json &&
90 + jq -e .System.StreamsOutbound < json &&
91 jq -e .Transient.Memory < json
92 '
93