Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: transport config #7479

Merged
merged 4 commits into from
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions cmd/ipfs/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ Headers.
cmds.BoolOption(migrateKwd, "If true, assume yes at the migrate prompt. If false, assume no."),
cmds.BoolOption(enablePubSubKwd, "Instantiate the ipfs daemon with the experimental pubsub feature enabled."),
cmds.BoolOption(enableIPNSPubSubKwd, "Enable IPNS record distribution through pubsub; enables pubsub."),
cmds.BoolOption(enableMultiplexKwd, "Add the experimental 'go-multiplex' stream muxer to libp2p on construction.").WithDefault(true),
cmds.BoolOption(enableMultiplexKwd, "DEPRECATED"),

// TODO: add way to override addresses. tricky part: updating the config if also --init.
// cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
Expand Down Expand Up @@ -296,7 +296,10 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
offline, _ := req.Options[offlineKwd].(bool)
ipnsps, _ := req.Options[enableIPNSPubSubKwd].(bool)
pubsub, _ := req.Options[enablePubSubKwd].(bool)
mplex, _ := req.Options[enableMultiplexKwd].(bool)
if _, hasMplex := req.Options[enableMultiplexKwd]; hasMplex {
log.Errorf("The mplex multiplexer has been enabled by default and the experimental %s flag has been removed.")
log.Errorf("To disable this multiplexer, please configure `Swarm.Transports.Multiplexers'.")
}

// Start assembling node config
ncfg := &core.BuildCfg{
Expand All @@ -307,7 +310,6 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
ExtraOpts: map[string]bool{
"pubsub": pubsub,
"ipnsps": ipnsps,
"mplex": mplex,
},
//TODO(Kubuxu): refactor Online vs Offline by adding Permanent vs Ephemeral
}
Expand Down
27 changes: 21 additions & 6 deletions core/node/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
blockstore "github.com/ipfs/go-ipfs-blockstore"
config "github.com/ipfs/go-ipfs-config"
util "github.com/ipfs/go-ipfs-util"
log "github.com/ipfs/go-log"
peer "github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"

Expand All @@ -22,12 +23,12 @@ import (
"go.uber.org/fx"
)

var logger = log.Logger("core:constructor")

var BaseLibP2P = fx.Options(
fx.Provide(libp2p.UserAgent),
fx.Provide(libp2p.PNet),
fx.Provide(libp2p.ConnectionManager),
fx.Provide(libp2p.Transports),

fx.Provide(libp2p.Host),

fx.Provide(libp2p.DiscoveryHandler),
Expand Down Expand Up @@ -108,19 +109,33 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
autonat = fx.Provide(libp2p.AutoNATService(cfg.AutoNAT.Throttle))
}

// Gather all the options
// If `cfg.Swarm.DisableRelay` is set and `Network.Relay` isn't, use the former.
enableRelay := cfg.Swarm.Transports.Network.Relay.WithDefault(!cfg.Swarm.DisableRelay) //nolint

// Warn about a deprecated option.
//nolint
if cfg.Swarm.DisableRelay {
logger.Error("The `Swarm.DisableRelay' config field is deprecated.")
if enableRelay {
logger.Error("`Swarm.DisableRelay' has been overridden by `Swarm.Transports.Network.Relay'")
} else {
logger.Error("Use the `Swarm.Transports.Network.Relay' config field instead")
}
}

// Gather all the options
opts := fx.Options(
BaseLibP2P,

fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)),
fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.NoAnnounce)),
fx.Provide(libp2p.SmuxTransport(bcfg.getOpt("mplex"))),
fx.Provide(libp2p.Relay(cfg.Swarm.DisableRelay, cfg.Swarm.EnableRelayHop)),
fx.Provide(libp2p.SmuxTransport(cfg.Swarm.Transports)),
fx.Provide(libp2p.Relay(enableRelay, cfg.Swarm.EnableRelayHop)),
fx.Provide(libp2p.Transports(cfg.Swarm.Transports)),
fx.Invoke(libp2p.StartListening(cfg.Addresses.Swarm)),
fx.Invoke(libp2p.SetupDiscovery(cfg.Discovery.MDNS.Enabled, cfg.Discovery.MDNS.Interval)),

fx.Provide(libp2p.Security(!bcfg.DisableEncryptedConnections, cfg.Experimental.OverrideSecurityTransports)),
fx.Provide(libp2p.Security(!bcfg.DisableEncryptedConnections, cfg.Swarm.Transports)),

fx.Provide(libp2p.Routing),
fx.Provide(libp2p.BaseRouting),
Expand Down
31 changes: 31 additions & 0 deletions core/node/libp2p/libp2p.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package libp2p

import (
"sort"
"time"

version "github.com/ipfs/go-ipfs"
config "github.com/ipfs/go-ipfs-config"

logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
Expand Down Expand Up @@ -48,3 +50,32 @@ func simpleOpt(opt libp2p.Option) func() (opts Libp2pOpts, err error) {
return
}
}

type priorityOption struct {
priority, defaultPriority config.Priority
opt libp2p.Option
}

func prioritizeOptions(opts []priorityOption) libp2p.Option {
type popt struct {
priority int64
opt libp2p.Option
}
enabledOptions := make([]popt, 0, len(opts))
for _, o := range opts {
if prio, ok := o.priority.WithDefault(o.defaultPriority); ok {
enabledOptions = append(enabledOptions, popt{
priority: prio,
opt: o.opt,
})
}
}
sort.Slice(enabledOptions, func(i, j int) bool {
return enabledOptions[i].priority > enabledOptions[j].priority
})
p2pOpts := make([]libp2p.Option, len(enabledOptions))
for i, opt := range enabledOptions {
p2pOpts[i] = opt.opt
}
return libp2p.ChainOptions(p2pOpts...)
}
9 changes: 4 additions & 5 deletions core/node/libp2p/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@ import (
relay "github.com/libp2p/go-libp2p-circuit"
)

func Relay(disable, enableHop bool) func() (opts Libp2pOpts, err error) {
func Relay(enableRelay, enableHop bool) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
if disable {
// Enabled by default.
opts.Opts = append(opts.Opts, libp2p.DisableRelay())
} else {
if enableRelay {
relayOpts := []relay.RelayOpt{}
if enableHop {
relayOpts = append(relayOpts, relay.OptHop)
}
opts.Opts = append(opts.Opts, libp2p.EnableRelay(relayOpts...))
} else {
opts.Opts = append(opts.Opts, libp2p.DisableRelay())
Stebalien marked this conversation as resolved.
Show resolved Hide resolved
}
return
}
Expand Down
38 changes: 38 additions & 0 deletions core/node/libp2p/sec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package libp2p

import (
config "github.com/ipfs/go-ipfs-config"
"github.com/libp2p/go-libp2p"
noise "github.com/libp2p/go-libp2p-noise"
secio "github.com/libp2p/go-libp2p-secio"
tls "github.com/libp2p/go-libp2p-tls"
)

func Security(enabled bool, tptConfig config.Transports) interface{} {
if !enabled {
return func() (opts Libp2pOpts) {
log.Errorf(`Your IPFS node has been configured to run WITHOUT ENCRYPTED CONNECTIONS.
You will not be able to connect to any nodes configured to use encrypted connections`)
opts.Opts = append(opts.Opts, libp2p.NoSecurity)
return opts
}
}

// Using the new config options.
return func() (opts Libp2pOpts) {
opts.Opts = append(opts.Opts, prioritizeOptions([]priorityOption{{
priority: tptConfig.Security.TLS,
defaultPriority: 100,
opt: libp2p.Security(tls.ID, tls.New),
}, {
priority: tptConfig.Security.SECIO,
defaultPriority: 200,
opt: libp2p.Security(secio.ID, secio.New),
}, {
priority: tptConfig.Security.Noise,
defaultPriority: 300,
opt: libp2p.Security(noise.ID, noise.New),
}}))
return opts
}
}
79 changes: 52 additions & 27 deletions core/node/libp2p/smux.go
Original file line number Diff line number Diff line change
@@ -1,54 +1,79 @@
package libp2p

import (
"fmt"
"os"
"strings"

config "github.com/ipfs/go-ipfs-config"
"github.com/libp2p/go-libp2p"
smux "github.com/libp2p/go-libp2p-core/mux"
mplex "github.com/libp2p/go-libp2p-mplex"
yamux "github.com/libp2p/go-libp2p-yamux"
)

func makeSmuxTransportOption(mplexExp bool) libp2p.Option {
func yamuxTransport() smux.Multiplexer {
tpt := *yamux.DefaultTransport
tpt.AcceptBacklog = 512
if os.Getenv("YAMUX_DEBUG") != "" {
tpt.LogOutput = os.Stderr
}

return &tpt
}

func makeSmuxTransportOption(tptConfig config.Transports) (libp2p.Option, error) {
const yamuxID = "/yamux/1.0.0"
const mplexID = "/mplex/6.7.0"

ymxtpt := *yamux.DefaultTransport
ymxtpt.AcceptBacklog = 512

if os.Getenv("YAMUX_DEBUG") != "" {
ymxtpt.LogOutput = os.Stderr
}

muxers := map[string]smux.Multiplexer{yamuxID: &ymxtpt}
if mplexExp {
muxers[mplexID] = mplex.DefaultTransport
}

// Allow muxer preference order overriding
order := []string{yamuxID, mplexID}
if prefs := os.Getenv("LIBP2P_MUX_PREFS"); prefs != "" {
order = strings.Fields(prefs)
}
// Using legacy LIBP2P_MUX_PREFS variable.
log.Error("LIBP2P_MUX_PREFS is now deprecated.")
log.Error("Use the `Swarm.Transports.Multiplexers' config field.")
muxers := strings.Fields(prefs)
enabled := make(map[string]bool, len(muxers))

opts := make([]libp2p.Option, 0, len(order))
for _, id := range order {
tpt, ok := muxers[id]
if !ok {
log.Warn("unknown or duplicate muxer in LIBP2P_MUX_PREFS: %s", id)
continue
var opts []libp2p.Option
for _, tpt := range muxers {
if enabled[tpt] {
return nil, fmt.Errorf(
"duplicate muxer found in LIBP2P_MUX_PREFS: %s",
tpt,
)
}
switch tpt {
case yamuxID:
opts = append(opts, libp2p.Muxer(tpt, yamuxTransport))
case mplexID:
opts = append(opts, libp2p.Muxer(tpt, mplex.DefaultTransport))
default:
return nil, fmt.Errorf("unknown muxer: %s", tpt)
}
}
delete(muxers, id)
opts = append(opts, libp2p.Muxer(id, tpt))
return libp2p.ChainOptions(opts...), nil
} else {
return prioritizeOptions([]priorityOption{{
priority: tptConfig.Multiplexers.Yamux,
defaultPriority: 100,
opt: libp2p.Muxer(yamuxID, yamuxTransport),
}, {
priority: tptConfig.Multiplexers.Mplex,
defaultPriority: 200,
opt: libp2p.Muxer(mplexID, mplex.DefaultTransport),
}}), nil
}

return libp2p.ChainOptions(opts...)
}

func SmuxTransport(mplex bool) func() (opts Libp2pOpts, err error) {
func SmuxTransport(tptConfig config.Transports) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
opts.Opts = append(opts.Opts, makeSmuxTransportOption(mplex))
return
res, err := makeSmuxTransportOption(tptConfig)
if err != nil {
return opts, err
}
opts.Opts = append(opts.Opts, res)
return opts, nil
}
}
71 changes: 26 additions & 45 deletions core/node/libp2p/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,44 @@ package libp2p
import (
"fmt"

"github.com/libp2p/go-libp2p"
config "github.com/ipfs/go-ipfs-config"
libp2p "github.com/libp2p/go-libp2p"
metrics "github.com/libp2p/go-libp2p-core/metrics"
noise "github.com/libp2p/go-libp2p-noise"
libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
secio "github.com/libp2p/go-libp2p-secio"
tls "github.com/libp2p/go-libp2p-tls"
tcp "github.com/libp2p/go-tcp-transport"
websocket "github.com/libp2p/go-ws-transport"

"go.uber.org/fx"
)

// default security transports for libp2p
var defaultSecurityTransports = []string{"tls", "secio", "noise"}
func Transports(tptConfig config.Transports) interface{} {
return func(pnet struct {
fx.In
Fprint PNetFingerprint `optional:"true"`
}) (opts Libp2pOpts, err error) {
Stebalien marked this conversation as resolved.
Show resolved Hide resolved
privateNetworkEnabled := pnet.Fprint != nil

func Transports(pnet struct {
fx.In
Fprint PNetFingerprint `optional:"true"`
}) (opts Libp2pOpts) {
opts.Opts = append(opts.Opts, libp2p.DefaultTransports)
if pnet.Fprint == nil {
opts.Opts = append(opts.Opts, libp2p.Transport(libp2pquic.NewTransport))
}
return opts
}

func Security(enabled bool, securityTransportOverride []string) interface{} {
if !enabled {
return func() (opts Libp2pOpts) {
// TODO: shouldn't this be Errorf to guarantee visibility?
log.Warnf(`Your IPFS node has been configured to run WITHOUT ENCRYPTED CONNECTIONS.
You will not be able to connect to any nodes configured to use encrypted connections`)
opts.Opts = append(opts.Opts, libp2p.NoSecurity)
return opts
if tptConfig.Network.TCP.WithDefault(true) {
opts.Opts = append(opts.Opts, libp2p.Transport(tcp.NewTCPTransport))
}
}

securityTransports := defaultSecurityTransports
if len(securityTransportOverride) > 0 {
securityTransports = securityTransportOverride
}
if tptConfig.Network.Websocket.WithDefault(true) {
opts.Opts = append(opts.Opts, libp2p.Transport(websocket.New))
}

var libp2pOpts []libp2p.Option
for _, tpt := range securityTransports {
switch tpt {
case "tls":
libp2pOpts = append(libp2pOpts, libp2p.Security(tls.ID, tls.New))
case "secio":
libp2pOpts = append(libp2pOpts, libp2p.Security(secio.ID, secio.New))
case "noise":
libp2pOpts = append(libp2pOpts, libp2p.Security(noise.ID, noise.New))
default:
return fx.Error(fmt.Errorf("invalid security transport specified in config: %s", tpt))
if tptConfig.Network.QUIC.WithDefault(!privateNetworkEnabled) {
if privateNetworkEnabled {
// QUIC was force enabled while the private network was turned on.
// Fail and tell the user.
return opts, fmt.Errorf(
"The QUIC transport does not support private networks. " +
"Please disable Swarm.Transports.Network.QUIC.",
)
}
opts.Opts = append(opts.Opts, libp2p.Transport(libp2pquic.NewTransport))
}
}

return func() (opts Libp2pOpts) {
opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2pOpts...))
return opts
return opts, nil
}
}

Expand Down