diff --git a/api/api_net.go b/api/api_net.go index 4cf9ca336..0a389e5ed 100644 --- a/api/api_net.go +++ b/api/api_net.go @@ -51,6 +51,9 @@ type Net interface { NetBlockRemove(ctx context.Context, acl NetBlockList) error //perm:admin NetBlockList(ctx context.Context) (NetBlockList, error) //perm:read + // ResourceManager API + NetStat(ctx context.Context, scope string) (NetStat, error) //perm:read + // ID returns peerID of libp2p node backing this API ID(context.Context) (peer.ID, error) //perm:read } diff --git a/api/types.go b/api/types.go index 81345306d..66fb79850 100644 --- a/api/types.go +++ b/api/types.go @@ -12,6 +12,7 @@ import ( "github.com/ipfs/go-cid" "github.com/ipfs/go-graphsync" + "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" pubsub "github.com/libp2p/go-libp2p-pubsub" ma "github.com/multiformats/go-multiaddr" @@ -129,6 +130,14 @@ type NetBlockList struct { IPSubnets []string } +type NetStat struct { + System *network.ScopeStat `json:",omitempty"` + Transient *network.ScopeStat `json:",omitempty"` + Services map[string]network.ScopeStat `json:",omitempty"` + Protocols map[string]network.ScopeStat `json:",omitempty"` + Peers map[string]network.ScopeStat +} + type ExtendedPeerInfo struct { ID peer.ID Agent string diff --git a/node/impl/net/net.go b/node/impl/net/net.go index a1003ffe5..27e7734a1 100644 --- a/node/impl/net/net.go +++ b/node/impl/net/net.go @@ -25,12 +25,13 @@ import ( type NetAPI struct { fx.In - RawHost lp2p.RawHost - Host host.Host - Router lp2p.BaseIpfsRouting - ConnGater *conngater.BasicConnectionGater - Reporter metrics.Reporter - Sk *dtypes.ScoreKeeper + RawHost lp2p.RawHost + Host host.Host + Router lp2p.BaseIpfsRouting + ConnGater *conngater.BasicConnectionGater + ResourceManager network.ResourceManager + Reporter metrics.Reporter + Sk *dtypes.ScoreKeeper } func (a *NetAPI) ID(context.Context) (peer.ID, error) { diff --git a/node/impl/net/rcmgr.go b/node/impl/net/rcmgr.go new file mode 100644 index 000000000..2084d3a35 --- /dev/null +++ b/node/impl/net/rcmgr.go @@ -0,0 +1,102 @@ +package net + +import ( + "context" + "strings" + + "golang.org/x/xerrors" + + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" + + "github.com/filecoin-project/lotus/api" +) + +func (a *NetAPI) NetStat(ctx context.Context, scope string) (result api.NetStat, err error) { + switch { + case scope == "all": + rapi, ok := a.ResourceManager.(rcmgr.ResourceManagerState) + if !ok { + return result, xerrors.Errorf("rexource manager does not support ResourceManagerState API") + } + + stat := rapi.Stat() + result.System = &stat.System + result.Transient = &stat.Transient + if len(stat.Services) > 0 { + result.Services = stat.Services + } + if len(stat.Protocols) > 0 { + result.Protocols = make(map[string]network.ScopeStat, len(stat.Protocols)) + for proto, stat := range stat.Protocols { + result.Protocols[string(proto)] = stat + } + } + if len(stat.Peers) > 0 { + result.Peers = make(map[string]network.ScopeStat, len(stat.Peers)) + for p, stat := range stat.Peers { + result.Peers[p.Pretty()] = stat + } + } + + return result, nil + + case scope == "system": + err = a.ResourceManager.ViewSystem(func(s network.ResourceScope) error { + stat := s.Stat() + result.System = &stat + return nil + }) + return result, err + + case scope == "transient": + err = a.ResourceManager.ViewTransient(func(s network.ResourceScope) error { + stat := s.Stat() + result.Transient = &stat + return nil + }) + return result, err + + case strings.HasPrefix(scope, "svc:"): + svc := scope[4:] + err = a.ResourceManager.ViewService(svc, func(s network.ServiceScope) error { + stat := s.Stat() + result.Services = map[string]network.ScopeStat{ + svc: stat, + } + return nil + }) + return result, err + + case strings.HasPrefix(scope, "proto:"): + proto := scope[6:] + err = a.ResourceManager.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { + stat := s.Stat() + result.Protocols = map[string]network.ScopeStat{ + proto: stat, + } + return nil + }) + return result, err + + case strings.HasPrefix(scope, "peer:"): + p := scope[5:] + pid, err := peer.IDFromString(p) + if err != nil { + return result, err + } + err = a.ResourceManager.ViewPeer(pid, func(s network.PeerScope) error { + stat := s.Stat() + result.Peers = map[string]network.ScopeStat{ + p: stat, + } + return nil + }) + return result, err + + default: + return result, xerrors.Errorf("invalid scope %s", scope) + } +}