From 2a1fb103431a1362828ee0341b2d025ec84722f9 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 27 Oct 2021 17:08:36 -0700 Subject: [PATCH] reuse the same router until we change listeners Technically, someone can set net.ipv4.ip_nonlocal_bind=1 to bind to non-existent IP addresses, but I'm comfortable making this change and seeing if anyone complains. I highly doubt it'll have any impact. If it doesn't work out, we have other options (e.g., catch the "invalid route" error and try again). fixes #238 --- go.mod | 1 + reuse.go | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 17ded7a..9b0f00e 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/golang/mock v1.6.0 + github.com/google/gopacket v1.1.17 github.com/ipfs/go-log v1.0.4 github.com/klauspost/compress v1.11.7 github.com/libp2p/go-libp2p-core v0.10.0 diff --git a/reuse.go b/reuse.go index 851df99..43eb2cd 100644 --- a/reuse.go +++ b/reuse.go @@ -5,6 +5,7 @@ import ( "sync" "time" + "github.com/google/gopacket/routing" "github.com/libp2p/go-netroute" ) @@ -54,6 +55,7 @@ type reuse struct { closeChan chan struct{} gcStopChan chan struct{} + routes routing.Router unicast map[string] /* IP.String() */ map[int] /* port */ *reuseConn // global contains connections that are listening on 0.0.0.0 / :: global map[int]*reuseConn @@ -108,6 +110,15 @@ func (r *reuse) gc() { } if len(conns) == 0 { delete(r.unicast, ukey) + // If we've dropped all connections with a unicast binding, + // assume our routes may have changed. + if len(r.unicast) == 0 { + r.routes = nil + } else { + // Ignore the error, there's nothing we can do about + // it. + r.routes, _ = netroute.New() + } } } r.mutex.Unlock() @@ -117,7 +128,15 @@ func (r *reuse) gc() { func (r *reuse) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) { var ip *net.IP - if router, err := netroute.New(); err == nil { + + // Only bother looking up the source address if we actually _have_ non 0.0.0.0 listeners. + // Otherwise, save some time. + + r.mutex.Lock() + router := r.routes + r.mutex.Unlock() + + if router != nil { _, _, src, err := router.Route(raddr.IP) if err == nil && !src.IsUnspecified() { ip = &src @@ -194,6 +213,9 @@ func (r *reuse) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) { // Deal with listen on a unicast address if _, ok := r.unicast[localAddr.IP.String()]; !ok { r.unicast[localAddr.IP.String()] = make(map[int]*reuseConn) + // Assume the system's routes may have changed if we're adding a new listener. + // Ignore the error, there's nothing we can do. + r.routes, _ = netroute.New() } // The kernel already checked that the laddr is not already listen