// Copyright © 2022 Ettore Di Giacinto // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see . package node import ( "fmt" "strings" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" libp2pprotocol "github.com/libp2p/go-libp2p-core/protocol" rcmgr "github.com/libp2p/go-libp2p-resource-manager" ) type NetLimitConfig struct { Dynamic bool `json:",omitempty"` // set if Dynamic is false Memory int64 `json:",omitempty"` // set if Dynamic is true MemoryFraction float64 `json:",omitempty"` MinMemory int64 `json:",omitempty"` MaxMemory int64 `json:",omitempty"` Streams, StreamsInbound, StreamsOutbound int Conns, ConnsInbound, ConnsOutbound int FD int } func NetSetLimit(mgr network.ResourceManager, scope string, limit NetLimitConfig) error { setLimit := func(s network.ResourceScope) error { limiter, ok := s.(rcmgr.ResourceScopeLimiter) if !ok { return fmt.Errorf("resource scope doesn't implement ResourceScopeLimiter interface") } var newLimit rcmgr.Limit if limit.Dynamic { newLimit = &rcmgr.DynamicLimit{ MemoryLimit: rcmgr.MemoryLimit{ MemoryFraction: limit.MemoryFraction, MinMemory: limit.MinMemory, MaxMemory: limit.MaxMemory, }, BaseLimit: rcmgr.BaseLimit{ Streams: limit.Streams, StreamsInbound: limit.StreamsInbound, StreamsOutbound: limit.StreamsOutbound, Conns: limit.Conns, ConnsInbound: limit.ConnsInbound, ConnsOutbound: limit.ConnsOutbound, FD: limit.FD, }, } } else { newLimit = &rcmgr.StaticLimit{ Memory: limit.Memory, BaseLimit: rcmgr.BaseLimit{ Streams: limit.Streams, StreamsInbound: limit.StreamsInbound, StreamsOutbound: limit.StreamsOutbound, Conns: limit.Conns, ConnsInbound: limit.ConnsInbound, ConnsOutbound: limit.ConnsOutbound, FD: limit.FD, }, } } limiter.SetLimit(newLimit) return nil } switch { case scope == "system": err := mgr.ViewSystem(func(s network.ResourceScope) error { return setLimit(s) }) return err case scope == "transient": err := mgr.ViewTransient(func(s network.ResourceScope) error { return setLimit(s) }) return err case strings.HasPrefix(scope, "svc:"): svc := scope[4:] err := mgr.ViewService(svc, func(s network.ServiceScope) error { return setLimit(s) }) return err case strings.HasPrefix(scope, "proto:"): proto := scope[6:] err := mgr.ViewProtocol(libp2pprotocol.ID(proto), func(s network.ProtocolScope) error { return setLimit(s) }) return err case strings.HasPrefix(scope, "peer:"): p := scope[5:] pid, err := peer.Decode(p) if err != nil { return fmt.Errorf("invalid peer ID: %s: %w", p, err) } err = mgr.ViewPeer(pid, func(s network.PeerScope) error { return setLimit(s) }) return err default: return fmt.Errorf("invalid scope %s", scope) } }