mirror of
https://github.com/libp2p/go-libp2p.git
synced 2026-04-23 00:27:05 +08:00
swarm: make black hole detection configurable (#2403)
* swarm: make black hole detection configurable * address review comments
This commit is contained in:
+5
-1
@@ -126,6 +126,8 @@ type Config struct {
|
||||
PrometheusRegisterer prometheus.Registerer
|
||||
|
||||
DialRanker network.DialRanker
|
||||
|
||||
SwarmOpts []swarm.Option
|
||||
}
|
||||
|
||||
func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swarm, error) {
|
||||
@@ -160,7 +162,7 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := make([]swarm.Option, 0, 6)
|
||||
opts := cfg.SwarmOpts
|
||||
if cfg.Reporter != nil {
|
||||
opts = append(opts, swarm.WithMetrics(cfg.Reporter))
|
||||
}
|
||||
@@ -176,11 +178,13 @@ func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swa
|
||||
if cfg.MultiaddrResolver != nil {
|
||||
opts = append(opts, swarm.WithMultiaddrResolver(cfg.MultiaddrResolver))
|
||||
}
|
||||
|
||||
dialRanker := cfg.DialRanker
|
||||
if dialRanker == nil {
|
||||
dialRanker = swarm.NoDelayDialRanker
|
||||
}
|
||||
opts = append(opts, swarm.WithDialRanker(dialRanker))
|
||||
|
||||
if enableMetrics {
|
||||
opts = append(opts,
|
||||
swarm.WithMetricsTracer(swarm.NewMetricsTracer(swarm.WithRegisterer(cfg.PrometheusRegisterer))))
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
|
||||
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/swarm"
|
||||
tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader"
|
||||
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
|
||||
@@ -587,3 +588,11 @@ func DialRanker(d network.DialRanker) Option {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SwarmOpts configures libp2p to use swarm with opts
|
||||
func SwarmOpts(opts ...swarm.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.SwarmOpts = opts
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,17 +241,36 @@ func (d *blackHoleDetector) RecordResult(addr ma.Multiaddr, success bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func newBlackHoleDetector(detectUDP, detectIPv6 bool, mt MetricsTracer) *blackHoleDetector {
|
||||
// blackHoleConfig is the config used for black hole detection
|
||||
type blackHoleConfig struct {
|
||||
// Enabled enables black hole detection
|
||||
Enabled bool
|
||||
// N is the size of the sliding window used to evaluate black hole state
|
||||
N int
|
||||
// MinSuccesses is the minimum number of successes out of N required to not
|
||||
// block requests
|
||||
MinSuccesses int
|
||||
}
|
||||
|
||||
func newBlackHoleDetector(udpConfig, ipv6Config blackHoleConfig, mt MetricsTracer) *blackHoleDetector {
|
||||
d := &blackHoleDetector{}
|
||||
|
||||
// A black hole is a binary property. On a network if UDP dials are blocked or there is
|
||||
// no IPv6 connectivity, all dials will fail. So a low success rate of 5 out 100 dials
|
||||
// is good enough.
|
||||
if detectUDP {
|
||||
d.udp = &blackHoleFilter{n: 100, minSuccesses: 5, name: "UDP", metricsTracer: mt}
|
||||
if udpConfig.Enabled {
|
||||
d.udp = &blackHoleFilter{
|
||||
n: udpConfig.N,
|
||||
minSuccesses: udpConfig.MinSuccesses,
|
||||
name: "UDP",
|
||||
metricsTracer: mt,
|
||||
}
|
||||
}
|
||||
if detectIPv6 {
|
||||
d.ipv6 = &blackHoleFilter{n: 100, minSuccesses: 5, name: "IPv6", metricsTracer: mt}
|
||||
|
||||
if ipv6Config.Enabled {
|
||||
d.ipv6 = &blackHoleFilter{
|
||||
n: ipv6Config.N,
|
||||
minSuccesses: ipv6Config.MinSuccesses,
|
||||
name: "IPv6",
|
||||
metricsTracer: mt,
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
@@ -75,7 +75,9 @@ func TestBlackHoleFilterSuccessFraction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlackHoleDetectorInApplicableAddress(t *testing.T) {
|
||||
bhd := newBlackHoleDetector(true, true, nil)
|
||||
udpConfig := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5}
|
||||
ipv6Config := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5}
|
||||
bhd := newBlackHoleDetector(udpConfig, ipv6Config, nil)
|
||||
addrs := []ma.Multiaddr{
|
||||
ma.StringCast("/ip4/1.2.3.4/tcp/1234"),
|
||||
ma.StringCast("/ip4/1.2.3.4/tcp/1233"),
|
||||
@@ -92,7 +94,8 @@ func TestBlackHoleDetectorInApplicableAddress(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlackHoleDetectorUDPDisabled(t *testing.T) {
|
||||
bhd := newBlackHoleDetector(false, true, nil)
|
||||
ipv6Config := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5}
|
||||
bhd := newBlackHoleDetector(blackHoleConfig{Enabled: false}, ipv6Config, nil)
|
||||
publicAddr := ma.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1")
|
||||
privAddr := ma.StringCast("/ip4/192.168.1.5/udp/1234/quic-v1")
|
||||
for i := 0; i < 100; i++ {
|
||||
@@ -103,7 +106,8 @@ func TestBlackHoleDetectorUDPDisabled(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlackHoleDetectorIPv6Disabled(t *testing.T) {
|
||||
bhd := newBlackHoleDetector(true, false, nil)
|
||||
udpConfig := blackHoleConfig{Enabled: true, N: 10, MinSuccesses: 5}
|
||||
bhd := newBlackHoleDetector(udpConfig, blackHoleConfig{Enabled: false}, nil)
|
||||
publicAddr := ma.StringCast("/ip6/1::1/tcp/1234")
|
||||
privAddr := ma.StringCast("/ip6/::1/tcp/1234")
|
||||
addrs := []ma.Multiaddr{publicAddr, privAddr}
|
||||
|
||||
+30
-2
@@ -108,6 +108,26 @@ func WithDialRanker(d network.DialRanker) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithUDPBlackHoleConfig configures swarm to use c as the config for UDP black hole detection
|
||||
// n is the size of the sliding window used to evaluate black hole state
|
||||
// min is the minimum number of successes out of n required to not block requests
|
||||
func WithUDPBlackHoleConfig(enabled bool, n, min int) Option {
|
||||
return func(s *Swarm) error {
|
||||
s.udpBlackHoleConfig = blackHoleConfig{Enabled: enabled, N: n, MinSuccesses: min}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPv6BlackHoleConfig configures swarm to use c as the config for IPv6 black hole detection
|
||||
// n is the size of the sliding window used to evaluate black hole state
|
||||
// min is the minimum number of successes out of n required to not block requests
|
||||
func WithIPv6BlackHoleConfig(enabled bool, n, min int) Option {
|
||||
return func(s *Swarm) error {
|
||||
s.ipv6BlackHoleConfig = blackHoleConfig{Enabled: enabled, N: n, MinSuccesses: min}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Swarm is a connection muxer, allowing connections to other peers to
|
||||
// be opened and closed, while still using the same Chan for all
|
||||
// communication. The Chan sends/receives Messages, which note the
|
||||
@@ -174,7 +194,9 @@ type Swarm struct {
|
||||
|
||||
dialRanker network.DialRanker
|
||||
|
||||
bhd *blackHoleDetector
|
||||
udpBlackHoleConfig blackHoleConfig
|
||||
ipv6BlackHoleConfig blackHoleConfig
|
||||
bhd *blackHoleDetector
|
||||
}
|
||||
|
||||
// NewSwarm constructs a Swarm.
|
||||
@@ -194,6 +216,12 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts
|
||||
dialTimeoutLocal: defaultDialTimeoutLocal,
|
||||
maResolver: madns.DefaultResolver,
|
||||
dialRanker: DefaultDialRanker,
|
||||
|
||||
// A black hole is a binary property. On a network if UDP dials are blocked or there is
|
||||
// no IPv6 connectivity, all dials will fail. So a low success rate of 5 out 100 dials
|
||||
// is good enough.
|
||||
udpBlackHoleConfig: blackHoleConfig{Enabled: true, N: 100, MinSuccesses: 5},
|
||||
ipv6BlackHoleConfig: blackHoleConfig{Enabled: true, N: 100, MinSuccesses: 5},
|
||||
}
|
||||
|
||||
s.conns.m = make(map[peer.ID][]*Conn)
|
||||
@@ -215,7 +243,7 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts
|
||||
s.limiter = newDialLimiter(s.dialAddr)
|
||||
s.backf.init(s.ctx)
|
||||
|
||||
s.bhd = newBlackHoleDetector(true, true, s.metricsTracer)
|
||||
s.bhd = newBlackHoleDetector(s.udpBlackHoleConfig, s.ipv6BlackHoleConfig, s.metricsTracer)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user