lotus/cli/net.go

754 lines
16 KiB
Go
Raw Normal View History

2019-07-08 19:07:16 +00:00
package cli
import (
2020-07-31 08:27:22 +00:00
"encoding/json"
2019-07-08 19:07:16 +00:00
"fmt"
2020-07-31 08:27:22 +00:00
"os"
"sort"
"strings"
"text/tabwriter"
2019-07-08 19:07:16 +00:00
"github.com/dustin/go-humanize"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
2020-03-03 04:55:25 +00:00
"github.com/libp2p/go-libp2p-core/peer"
2020-09-02 23:31:41 +00:00
protocol "github.com/libp2p/go-libp2p-core/protocol"
"github.com/multiformats/go-multiaddr"
2020-03-03 04:55:25 +00:00
"github.com/filecoin-project/go-address"
atypes "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/addrutil"
2019-07-08 19:07:16 +00:00
)
2021-03-23 23:15:02 +00:00
var NetCmd = &cli.Command{
2019-07-08 19:07:16 +00:00
Name: "net",
Usage: "Manage P2P Network",
Subcommands: []*cli.Command{
2020-08-04 18:57:40 +00:00
NetPeers,
NetPing,
2021-03-23 23:15:02 +00:00
NetConnect,
2020-08-04 18:57:40 +00:00
NetListen,
NetId,
2021-03-23 23:15:02 +00:00
NetFindPeer,
NetScores,
NetReachability,
NetBandwidthCmd,
2020-11-13 12:27:44 +00:00
NetBlockCmd,
2022-01-18 14:28:20 +00:00
NetStatCmd,
NetLimitCmd,
2019-07-08 19:07:16 +00:00
},
}
2020-08-04 18:57:40 +00:00
var NetPeers = &cli.Command{
2019-07-08 19:07:16 +00:00
Name: "peers",
Usage: "Print peers",
2020-09-03 23:35:53 +00:00
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "agent",
Aliases: []string{"a"},
Usage: "Print agent name",
},
&cli.BoolFlag{
Name: "extended",
Aliases: []string{"x"},
Usage: "Print extended peer information in json",
},
2020-09-03 23:35:53 +00:00
},
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetAPI(cctx)
2019-07-10 17:28:49 +00:00
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
2019-07-18 23:16:23 +00:00
ctx := ReqContext(cctx)
2019-07-09 13:43:21 +00:00
peers, err := api.NetPeers(ctx)
if err != nil {
return err
}
sort.Slice(peers, func(i, j int) bool {
return strings.Compare(string(peers[i].ID), string(peers[j].ID)) > 0
})
if cctx.Bool("extended") {
2021-03-06 17:25:11 +00:00
// deduplicate
seen := make(map[peer.ID]struct{})
for _, peer := range peers {
2021-03-06 17:25:11 +00:00
_, dup := seen[peer.ID]
if dup {
continue
}
seen[peer.ID] = struct{}{}
info, err := api.NetPeerInfo(ctx, peer.ID)
2020-09-03 23:35:53 +00:00
if err != nil {
log.Warnf("error getting extended peer info: %s", err)
2020-09-03 23:35:53 +00:00
} else {
bytes, err := json.Marshal(&info)
if err != nil {
log.Warnf("error marshalling extended peer info: %s", err)
} else {
fmt.Println(string(bytes))
}
2020-09-03 23:35:53 +00:00
}
}
} else {
for _, peer := range peers {
var agent string
if cctx.Bool("agent") {
2021-03-08 12:31:06 +00:00
agent, err = api.NetAgentVersion(ctx, peer.ID)
if err != nil {
log.Warnf("getting agent version: %s", err)
} else {
agent = ", " + agent
}
}
fmt.Printf("%s, %s%s\n", peer.ID, peer.Addrs, agent)
}
}
return nil
},
}
var NetPing = &cli.Command{
Name: "ping",
Usage: "Ping peers",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "count",
Value: 10,
Aliases: []string{"c"},
Usage: "specify the number of times it should ping",
},
},
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() != 1 {
return xerrors.Errorf("please provide a peerID")
}
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
peerID, err := peer.Decode(cctx.Args().First())
if err != nil {
return xerrors.Errorf("failed to parse peerID: %v", err)
}
count := cctx.Int("count")
for i := 0; i < count; i++ {
RTT, err := api.NetPing(ctx, peerID)
if err != nil {
log.Errorf("ping failed: %v", err)
continue
}
fmt.Printf("ping %d, %v\n", i, RTT)
}
return nil
},
}
2021-03-23 23:15:02 +00:00
var NetScores = &cli.Command{
Name: "scores",
Usage: "Print peers' pubsub scores",
2020-07-31 08:27:22 +00:00
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "extended",
Aliases: []string{"x"},
Usage: "print extended peer scores in json",
2020-07-31 08:27:22 +00:00
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
scores, err := api.NetPubsubScores(ctx)
if err != nil {
return err
}
2020-07-31 08:27:22 +00:00
if cctx.Bool("extended") {
enc := json.NewEncoder(os.Stdout)
for _, peer := range scores {
err := enc.Encode(peer)
if err != nil {
return err
}
}
} else {
for _, peer := range scores {
fmt.Printf("%s, %f\n", peer.ID, peer.Score.Score)
}
2019-07-09 13:43:21 +00:00
}
2019-07-08 19:07:16 +00:00
return nil
},
}
2020-08-04 18:57:40 +00:00
var NetListen = &cli.Command{
2019-07-08 21:01:15 +00:00
Name: "listen",
Usage: "List listen addresses",
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetAPI(cctx)
2019-07-10 17:28:49 +00:00
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
2019-07-18 23:16:23 +00:00
ctx := ReqContext(cctx)
2019-07-08 21:01:15 +00:00
2019-07-09 13:43:21 +00:00
addrs, err := api.NetAddrsListen(ctx)
if err != nil {
return err
}
2019-07-09 17:03:36 +00:00
for _, peer := range addrs.Addrs {
fmt.Printf("%s/p2p/%s\n", peer, addrs.ID)
2019-07-09 13:43:21 +00:00
}
2019-07-08 21:01:15 +00:00
return nil
},
}
2021-03-23 23:15:02 +00:00
var NetConnect = &cli.Command{
Name: "connect",
Usage: "Connect to a peer",
ArgsUsage: "[peerMultiaddr|minerActorAddress]",
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetAPI(cctx)
2019-07-10 17:28:49 +00:00
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
2019-07-18 23:16:23 +00:00
ctx := ReqContext(cctx)
pis, err := addrutil.ParseAddresses(ctx, cctx.Args().Slice())
2019-07-08 19:07:16 +00:00
if err != nil {
a, perr := address.NewFromString(cctx.Args().First())
if perr != nil {
return err
}
na, fc, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer fc()
mi, err := na.StateMinerInfo(ctx, a, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
if mi.PeerId == nil {
return xerrors.Errorf("no PeerID for miner")
}
multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs))
for i, a := range mi.Multiaddrs {
maddr, err := multiaddr.NewMultiaddrBytes(a)
if err != nil {
log.Warnf("parsing multiaddr %d (%x): %s", i, a, err)
continue
}
multiaddrs = append(multiaddrs, maddr)
}
pi := peer.AddrInfo{
ID: *mi.PeerId,
Addrs: multiaddrs,
}
fmt.Printf("%s -> %s\n", a, pi)
pis = append(pis, pi)
2019-07-08 19:07:16 +00:00
}
for _, pi := range pis {
fmt.Printf("connect %s: ", pi.ID.Pretty())
err := api.NetConnect(ctx, pi)
2019-07-08 19:07:16 +00:00
if err != nil {
fmt.Println("failure")
return err
}
fmt.Println("success")
}
return nil
},
}
2020-08-04 18:57:40 +00:00
var NetId = &cli.Command{
2019-07-22 17:20:07 +00:00
Name: "id",
Usage: "Get node identity",
Action: func(cctx *cli.Context) error {
2019-10-03 18:12:30 +00:00
api, closer, err := GetAPI(cctx)
2019-07-22 17:20:07 +00:00
if err != nil {
return err
}
2019-10-03 18:12:30 +00:00
defer closer()
2019-07-22 17:20:07 +00:00
2019-07-18 23:16:23 +00:00
ctx := ReqContext(cctx)
2019-07-22 17:20:07 +00:00
pid, err := api.ID(ctx)
if err != nil {
return err
}
fmt.Println(pid)
return nil
},
}
2021-03-23 23:15:02 +00:00
var NetFindPeer = &cli.Command{
Name: "findpeer",
Usage: "Find the addresses of a given peerID",
ArgsUsage: "[peerId]",
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
fmt.Println("Usage: findpeer [peer ID]")
return nil
}
pid, err := peer.Decode(cctx.Args().First())
if err != nil {
return err
}
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
addrs, err := api.NetFindPeer(ctx, pid)
if err != nil {
return err
}
fmt.Println(addrs)
return nil
},
}
2020-08-13 11:18:14 +00:00
var NetReachability = &cli.Command{
2020-08-13 11:44:43 +00:00
Name: "reachability",
Usage: "Print information about reachability from the internet",
2020-08-13 11:18:14 +00:00
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
i, err := api.NetAutoNatStatus(ctx)
if err != nil {
return err
}
fmt.Println("AutoNAT status: ", i.Reachability.String())
2020-08-18 01:12:50 +00:00
if i.PublicAddr != "" {
fmt.Println("Public address: ", i.PublicAddr)
2020-08-13 11:18:14 +00:00
}
return nil
},
}
var NetBandwidthCmd = &cli.Command{
Name: "bandwidth",
Usage: "Print bandwidth usage information",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "by-peer",
Usage: "list bandwidth usage by peer",
},
&cli.BoolFlag{
Name: "by-protocol",
Usage: "list bandwidth usage by protocol",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
bypeer := cctx.Bool("by-peer")
byproto := cctx.Bool("by-protocol")
tw := tabwriter.NewWriter(os.Stdout, 4, 4, 2, ' ', 0)
fmt.Fprintf(tw, "Segment\tTotalIn\tTotalOut\tRateIn\tRateOut\n")
if bypeer {
bw, err := api.NetBandwidthStatsByPeer(ctx)
if err != nil {
return err
}
var peers []string
for p := range bw {
peers = append(peers, p)
}
sort.Slice(peers, func(i, j int) bool {
return peers[i] < peers[j]
})
for _, p := range peers {
s := bw[p]
fmt.Fprintf(tw, "%s\t%s\t%s\t%s/s\t%s/s\n", p, humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
}
} else if byproto {
bw, err := api.NetBandwidthStatsByProtocol(ctx)
if err != nil {
return err
}
var protos []protocol.ID
for p := range bw {
protos = append(protos, p)
}
sort.Slice(protos, func(i, j int) bool {
return protos[i] < protos[j]
})
for _, p := range protos {
s := bw[p]
if p == "" {
p = "<unknown>"
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%s/s\t%s/s\n", p, humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
}
} else {
s, err := api.NetBandwidthStats(ctx)
if err != nil {
return err
}
fmt.Fprintf(tw, "Total\t%s\t%s\t%s/s\t%s/s\n", humanize.Bytes(uint64(s.TotalIn)), humanize.Bytes(uint64(s.TotalOut)), humanize.Bytes(uint64(s.RateIn)), humanize.Bytes(uint64(s.RateOut)))
}
return tw.Flush()
},
}
2020-11-13 12:27:44 +00:00
var NetBlockCmd = &cli.Command{
Name: "block",
Usage: "Manage network connection gating rules",
Subcommands: []*cli.Command{
NetBlockAddCmd,
NetBlockRemoveCmd,
NetBlockListCmd,
},
}
var NetBlockAddCmd = &cli.Command{
Name: "add",
Usage: "Add connection gating rules",
Subcommands: []*cli.Command{
NetBlockAddPeer,
NetBlockAddIP,
NetBlockAddSubnet,
},
}
var NetBlockAddPeer = &cli.Command{
Name: "peer",
Usage: "Block a peer",
ArgsUsage: "<Peer> ...",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
var peers []peer.ID
for _, s := range cctx.Args().Slice() {
p, err := peer.Decode(s)
if err != nil {
return err
}
peers = append(peers, p)
}
return api.NetBlockAdd(ctx, atypes.NetBlockList{Peers: peers})
2020-11-13 12:27:44 +00:00
},
}
var NetBlockAddIP = &cli.Command{
Name: "ip",
Usage: "Block an IP address",
ArgsUsage: "<IP> ...",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
return api.NetBlockAdd(ctx, atypes.NetBlockList{IPAddrs: cctx.Args().Slice()})
2020-11-13 12:27:44 +00:00
},
}
var NetBlockAddSubnet = &cli.Command{
2020-11-13 12:39:34 +00:00
Name: "subnet",
2020-11-13 12:27:44 +00:00
Usage: "Block an IP subnet",
ArgsUsage: "<CIDR> ...",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
return api.NetBlockAdd(ctx, atypes.NetBlockList{IPSubnets: cctx.Args().Slice()})
2020-11-13 12:27:44 +00:00
},
}
var NetBlockRemoveCmd = &cli.Command{
2020-11-13 12:39:34 +00:00
Name: "remove",
2020-11-13 12:27:44 +00:00
Usage: "Remove connection gating rules",
Subcommands: []*cli.Command{
NetBlockRemovePeer,
NetBlockRemoveIP,
NetBlockRemoveSubnet,
},
}
var NetBlockRemovePeer = &cli.Command{
Name: "peer",
Usage: "Unblock a peer",
ArgsUsage: "<Peer> ...",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
var peers []peer.ID
for _, s := range cctx.Args().Slice() {
p, err := peer.Decode(s)
if err != nil {
return err
}
peers = append(peers, p)
}
return api.NetBlockRemove(ctx, atypes.NetBlockList{Peers: peers})
2020-11-13 12:27:44 +00:00
},
}
var NetBlockRemoveIP = &cli.Command{
Name: "ip",
Usage: "Unblock an IP address",
ArgsUsage: "<IP> ...",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
return api.NetBlockRemove(ctx, atypes.NetBlockList{IPAddrs: cctx.Args().Slice()})
2020-11-13 12:27:44 +00:00
},
}
var NetBlockRemoveSubnet = &cli.Command{
2020-11-13 12:39:34 +00:00
Name: "subnet",
2020-11-13 12:27:44 +00:00
Usage: "Unblock an IP subnet",
ArgsUsage: "<CIDR> ...",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
return api.NetBlockRemove(ctx, atypes.NetBlockList{IPSubnets: cctx.Args().Slice()})
2020-11-13 12:27:44 +00:00
},
}
var NetBlockListCmd = &cli.Command{
Name: "list",
Usage: "list connection gating rules",
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
acl, err := api.NetBlockList(ctx)
if err != nil {
return err
}
if len(acl.Peers) != 0 {
sort.Slice(acl.Peers, func(i, j int) bool {
return strings.Compare(string(acl.Peers[i]), string(acl.Peers[j])) > 0
})
fmt.Println("Blocked Peers:")
for _, p := range acl.Peers {
fmt.Printf("\t%s\n", p)
}
}
if len(acl.IPAddrs) != 0 {
sort.Slice(acl.IPAddrs, func(i, j int) bool {
return strings.Compare(acl.IPAddrs[i], acl.IPAddrs[j]) < 0
})
fmt.Println("Blocked IPs:")
for _, a := range acl.IPAddrs {
fmt.Printf("\t%s\n", a)
}
}
if len(acl.IPSubnets) != 0 {
sort.Slice(acl.IPSubnets, func(i, j int) bool {
return strings.Compare(acl.IPSubnets[i], acl.IPSubnets[j]) < 0
})
fmt.Println("Blocked Subnets:")
for _, n := range acl.IPSubnets {
fmt.Printf("\t%s\n", n)
}
}
return nil
},
}
2022-01-18 14:28:20 +00:00
var NetStatCmd = &cli.Command{
Name: "stat",
Usage: "Report resource usage for a scope",
2022-01-18 14:28:20 +00:00
ArgsUsage: "scope",
Description: `Report resource usage for a scope.
The scope can be one of the following:
- system -- reports the system aggregate resource usage.
- transient -- reports the transient resource usage.
- svc:<service> -- reports the resource usage of a specific service.
- proto:<proto> -- reports the resource usage of a specific protocol.
- peer:<peer> -- reports the resource usage of a specific peer.
- all -- reports the resource usage for all currently active scopes.
`,
2022-01-18 14:28:20 +00:00
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
args := cctx.Args().Slice()
if len(args) != 1 {
return xerrors.Errorf("must specify exactly one scope")
}
scope := args[0]
result, err := api.NetStat(ctx, scope)
if err != nil {
return err
}
enc := json.NewEncoder(os.Stdout)
2022-01-20 09:46:39 +00:00
return enc.Encode(result)
2022-01-18 14:28:20 +00:00
},
}
var NetLimitCmd = &cli.Command{
Name: "limit",
Usage: "Get or set resource limits for a scope",
2022-01-18 14:28:20 +00:00
ArgsUsage: "scope [limit]",
Description: `Get or set resource limits for a scope.
The scope can be one of the following:
- system -- reports the system aggregate resource usage.
- transient -- reports the transient resource usage.
- svc:<service> -- reports the resource usage of a specific service.
- proto:<proto> -- reports the resource usage of a specific protocol.
- peer:<peer> -- reports the resource usage of a specific peer.
The limit is json-formatted, with the same structure as the limits file.
`,
2022-01-18 14:28:20 +00:00
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "set",
Usage: "set the limit for a scope",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
args := cctx.Args().Slice()
if cctx.Bool("set") {
if len(args) != 2 {
return xerrors.Errorf("must specify exactly a scope and a limit")
}
scope := args[0]
limitStr := args[1]
var limit atypes.NetLimit
err := json.Unmarshal([]byte(limitStr), &limit)
if err != nil {
return xerrors.Errorf("error decoding limit: %w", err)
}
return api.NetSetLimit(ctx, scope, limit)
2022-01-20 09:46:39 +00:00
}
2022-01-18 14:28:20 +00:00
2022-01-20 09:46:39 +00:00
if len(args) != 1 {
return xerrors.Errorf("must specify exactly one scope")
}
scope := args[0]
2022-01-18 14:28:20 +00:00
2022-01-20 09:46:39 +00:00
result, err := api.NetLimit(ctx, scope)
if err != nil {
return err
2022-01-18 14:28:20 +00:00
}
2022-01-20 09:46:39 +00:00
enc := json.NewEncoder(os.Stdout)
return enc.Encode(result)
2022-01-18 14:28:20 +00:00
},
}