swarm: make black hole detection configurable (#2403)

* swarm: make black hole detection configurable

* address review comments
This commit is contained in:
Sukun
2023-07-07 11:12:28 +05:30
committed by GitHub
parent cfc50bae8e
commit 757bf59136
5 changed files with 78 additions and 14 deletions
+5 -1
View File
@@ -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))))
+9
View File
@@ -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
}
}
+27 -8
View File
@@ -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
}
+7 -3
View File
@@ -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
View File
@@ -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
}