Repository: libp2p/go-libp2p
Pull request #2527 (2023-08-26 11:43:22)

config: warn if connmgr limits conflict with rcmgr
closes: #1707 

If the high water mark of the connection manager exceeds the total connection limit of the resource manager then a warning will be issued at node startup.

@MarcoPolo, I actually think it would be neater to pass an int to `CheckLimit` as opposed to what I've currently implemented. 
```go
CheckLimit(systemLimit connmgr.GetterConnLimit)
```
Let me know what you think

piersy: Hi @MarcoPolo could you elaborate on how to improve the warning message?

Currently the warnings would take the following format:

>conn manager high water limit: 8, exceeds the system limit of: 4
piersy: Hi @sukunrt, thanks for the review, I think I've addressed all your points.

Patch:
diff --git a/config/config.go b/config/config.go
index bb3a1213..64058425 100644
--- a/config/config.go
+++ b/config/config.go
@@ -295,6 +295,15 @@ func (cfg *Config) addTransports(h host.Host) error {
 //
 // This function consumes the config. Do not reuse it (really!).
 func (cfg *Config) NewNode() (host.Host, error) {
+	// If possible check that the resource manager conn limit is higher than the
+	// limit set in the conn manager.
+	if l, ok := cfg.ResourceManager.(connmgr.GetConnLimiter); ok {
+		err := cfg.ConnManager.CheckLimit(l)
+		if err != nil {
+			log.Warn(fmt.Sprintf("rcmgr limit conflicts with connmgr limit: %v", err))
+		}
+	}
+
 	eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer))))
 	swrm, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics)
 	if err != nil {
diff --git a/core/connmgr/manager.go b/core/connmgr/manager.go
index e0d6c520..d756e439 100644
--- a/core/connmgr/manager.go
+++ b/core/connmgr/manager.go
@@ -74,6 +74,10 @@ type ConnManager interface {
 	// then it will return true if the peer is protected for any tag
 	IsProtected(id peer.ID, tag string) (protected bool)
 
+	// CheckLimit will return an error if the connection manager's internal
+	// connection limit exceeds the provided system limit.
+	CheckLimit(l GetConnLimiter) error
+
 	// Close closes the connection manager and stops background processes.
 	Close() error
 }
@@ -89,3 +93,9 @@ type TagInfo struct {
 	// Conns maps connection ids (such as remote multiaddr) to their creation time.
 	Conns map[string]time.Time
 }
+
+// GetConnLimiter provides access to a component's total connection limit.
+type GetConnLimiter interface {
+	// GetConnLimit returns the total connection limit of the implementing component.
+	GetConnLimit() int
+}
diff --git a/core/connmgr/null.go b/core/connmgr/null.go
index 25743f4e..73541171 100644
--- a/core/connmgr/null.go
+++ b/core/connmgr/null.go
@@ -21,4 +21,5 @@ func (NullConnMgr) Notifee() network.Notifiee                { return network.Gl
 func (NullConnMgr) Protect(peer.ID, string)                  {}
 func (NullConnMgr) Unprotect(peer.ID, string) bool           { return false }
 func (NullConnMgr) IsProtected(peer.ID, string) bool         { return false }
+func (NullConnMgr) CheckLimit(l GetConnLimiter) error        { return nil }
 func (NullConnMgr) Close() error                             { return nil }
diff --git a/core/network/mocks/mock_conn_management_scope.go b/core/network/mocks/mock_conn_management_scope.go
index 1c018761..0b1ef5da 100644
--- a/core/network/mocks/mock_conn_management_scope.go
+++ b/core/network/mocks/mock_conn_management_scope.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ConnManagementScope)
-
+//
+// Generated by this command:
+//
+//	mockgen -package mocknetwork -destination mock_conn_management_scope.go github.com/libp2p/go-libp2p/core/network ConnManagementScope
+//
 // Package mocknetwork is a generated GoMock package.
 package mocknetwork
 
@@ -83,7 +87,7 @@ func (m *MockConnManagementScope) ReleaseMemory(arg0 int) {
 }
 
 // ReleaseMemory indicates an expected call of ReleaseMemory.
-func (mr *MockConnManagementScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call {
+func (mr *MockConnManagementScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockConnManagementScope)(nil).ReleaseMemory), arg0)
 }
@@ -97,7 +101,7 @@ func (m *MockConnManagementScope) ReserveMemory(arg0 int, arg1 byte) error {
 }
 
 // ReserveMemory indicates an expected call of ReserveMemory.
-func (mr *MockConnManagementScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockConnManagementScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockConnManagementScope)(nil).ReserveMemory), arg0, arg1)
 }
@@ -111,7 +115,7 @@ func (m *MockConnManagementScope) SetPeer(arg0 peer.ID) error {
 }
 
 // SetPeer indicates an expected call of SetPeer.
-func (mr *MockConnManagementScopeMockRecorder) SetPeer(arg0 interface{}) *gomock.Call {
+func (mr *MockConnManagementScopeMockRecorder) SetPeer(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPeer", reflect.TypeOf((*MockConnManagementScope)(nil).SetPeer), arg0)
 }
diff --git a/core/network/mocks/mock_peer_scope.go b/core/network/mocks/mock_peer_scope.go
index ce3f0e0d..6bc96bfa 100644
--- a/core/network/mocks/mock_peer_scope.go
+++ b/core/network/mocks/mock_peer_scope.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/network (interfaces: PeerScope)
-
+//
+// Generated by this command:
+//
+//	mockgen -package mocknetwork -destination mock_peer_scope.go github.com/libp2p/go-libp2p/core/network PeerScope
+//
 // Package mocknetwork is a generated GoMock package.
 package mocknetwork
 
@@ -71,7 +75,7 @@ func (m *MockPeerScope) ReleaseMemory(arg0 int) {
 }
 
 // ReleaseMemory indicates an expected call of ReleaseMemory.
-func (mr *MockPeerScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockPeerScope)(nil).ReleaseMemory), arg0)
 }
@@ -85,7 +89,7 @@ func (m *MockPeerScope) ReserveMemory(arg0 int, arg1 byte) error {
 }
 
 // ReserveMemory indicates an expected call of ReserveMemory.
-func (mr *MockPeerScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPeerScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockPeerScope)(nil).ReserveMemory), arg0, arg1)
 }
diff --git a/core/network/mocks/mock_protocol_scope.go b/core/network/mocks/mock_protocol_scope.go
index b1c4ee31..06225fc9 100644
--- a/core/network/mocks/mock_protocol_scope.go
+++ b/core/network/mocks/mock_protocol_scope.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ProtocolScope)
-
+//
+// Generated by this command:
+//
+//	mockgen -package mocknetwork -destination mock_protocol_scope.go github.com/libp2p/go-libp2p/core/network ProtocolScope
+//
 // Package mocknetwork is a generated GoMock package.
 package mocknetwork
 
@@ -71,7 +75,7 @@ func (m *MockProtocolScope) ReleaseMemory(arg0 int) {
 }
 
 // ReleaseMemory indicates an expected call of ReleaseMemory.
-func (mr *MockProtocolScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call {
+func (mr *MockProtocolScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockProtocolScope)(nil).ReleaseMemory), arg0)
 }
@@ -85,7 +89,7 @@ func (m *MockProtocolScope) ReserveMemory(arg0 int, arg1 byte) error {
 }
 
 // ReserveMemory indicates an expected call of ReserveMemory.
-func (mr *MockProtocolScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockProtocolScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockProtocolScope)(nil).ReserveMemory), arg0, arg1)
 }
diff --git a/core/network/mocks/mock_resource_manager.go b/core/network/mocks/mock_resource_manager.go
index ab6c2a2f..c43063dd 100644
--- a/core/network/mocks/mock_resource_manager.go
+++ b/core/network/mocks/mock_resource_manager.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ResourceManager)
-
+//
+// Generated by this command:
+//
+//	mockgen -package mocknetwork -destination mock_resource_manager.go github.com/libp2p/go-libp2p/core/network ResourceManager
+//
 // Package mocknetwork is a generated GoMock package.
 package mocknetwork
 
@@ -61,7 +65,7 @@ func (m *MockResourceManager) OpenConnection(arg0 network.Direction, arg1 bool,
 }
 
 // OpenConnection indicates an expected call of OpenConnection.
-func (mr *MockResourceManagerMockRecorder) OpenConnection(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) OpenConnection(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenConnection", reflect.TypeOf((*MockResourceManager)(nil).OpenConnection), arg0, arg1, arg2)
 }
@@ -76,7 +80,7 @@ func (m *MockResourceManager) OpenStream(arg0 peer.ID, arg1 network.Direction) (
 }
 
 // OpenStream indicates an expected call of OpenStream.
-func (mr *MockResourceManagerMockRecorder) OpenStream(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) OpenStream(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenStream", reflect.TypeOf((*MockResourceManager)(nil).OpenStream), arg0, arg1)
 }
@@ -90,7 +94,7 @@ func (m *MockResourceManager) ViewPeer(arg0 peer.ID, arg1 func(network.PeerScope
 }
 
 // ViewPeer indicates an expected call of ViewPeer.
-func (mr *MockResourceManagerMockRecorder) ViewPeer(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) ViewPeer(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewPeer", reflect.TypeOf((*MockResourceManager)(nil).ViewPeer), arg0, arg1)
 }
@@ -104,7 +108,7 @@ func (m *MockResourceManager) ViewProtocol(arg0 protocol.ID, arg1 func(network.P
 }
 
 // ViewProtocol indicates an expected call of ViewProtocol.
-func (mr *MockResourceManagerMockRecorder) ViewProtocol(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) ViewProtocol(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewProtocol", reflect.TypeOf((*MockResourceManager)(nil).ViewProtocol), arg0, arg1)
 }
@@ -118,7 +122,7 @@ func (m *MockResourceManager) ViewService(arg0 string, arg1 func(network.Service
 }
 
 // ViewService indicates an expected call of ViewService.
-func (mr *MockResourceManagerMockRecorder) ViewService(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) ViewService(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewService", reflect.TypeOf((*MockResourceManager)(nil).ViewService), arg0, arg1)
 }
@@ -132,7 +136,7 @@ func (m *MockResourceManager) ViewSystem(arg0 func(network.ResourceScope) error)
 }
 
 // ViewSystem indicates an expected call of ViewSystem.
-func (mr *MockResourceManagerMockRecorder) ViewSystem(arg0 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) ViewSystem(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewSystem", reflect.TypeOf((*MockResourceManager)(nil).ViewSystem), arg0)
 }
@@ -146,7 +150,7 @@ func (m *MockResourceManager) ViewTransient(arg0 func(network.ResourceScope) err
 }
 
 // ViewTransient indicates an expected call of ViewTransient.
-func (mr *MockResourceManagerMockRecorder) ViewTransient(arg0 interface{}) *gomock.Call {
+func (mr *MockResourceManagerMockRecorder) ViewTransient(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ViewTransient", reflect.TypeOf((*MockResourceManager)(nil).ViewTransient), arg0)
 }
diff --git a/core/network/mocks/mock_resource_scope_span.go b/core/network/mocks/mock_resource_scope_span.go
index 1f0ccae4..46518952 100644
--- a/core/network/mocks/mock_resource_scope_span.go
+++ b/core/network/mocks/mock_resource_scope_span.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/network (interfaces: ResourceScopeSpan)
-
+//
+// Generated by this command:
+//
+//	mockgen -package mocknetwork -destination mock_resource_scope_span.go github.com/libp2p/go-libp2p/core/network ResourceScopeSpan
+//
 // Package mocknetwork is a generated GoMock package.
 package mocknetwork
 
@@ -68,7 +72,7 @@ func (m *MockResourceScopeSpan) ReleaseMemory(arg0 int) {
 }
 
 // ReleaseMemory indicates an expected call of ReleaseMemory.
-func (mr *MockResourceScopeSpanMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call {
+func (mr *MockResourceScopeSpanMockRecorder) ReleaseMemory(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockResourceScopeSpan)(nil).ReleaseMemory), arg0)
 }
@@ -82,7 +86,7 @@ func (m *MockResourceScopeSpan) ReserveMemory(arg0 int, arg1 byte) error {
 }
 
 // ReserveMemory indicates an expected call of ReserveMemory.
-func (mr *MockResourceScopeSpanMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockResourceScopeSpanMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockResourceScopeSpan)(nil).ReserveMemory), arg0, arg1)
 }
diff --git a/core/network/mocks/mock_stream_management_scope.go b/core/network/mocks/mock_stream_management_scope.go
index 016c24e5..4470b2da 100644
--- a/core/network/mocks/mock_stream_management_scope.go
+++ b/core/network/mocks/mock_stream_management_scope.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/network (interfaces: StreamManagementScope)
-
+//
+// Generated by this command:
+//
+//	mockgen -package mocknetwork -destination mock_stream_management_scope.go github.com/libp2p/go-libp2p/core/network StreamManagementScope
+//
 // Package mocknetwork is a generated GoMock package.
 package mocknetwork
 
@@ -97,7 +101,7 @@ func (m *MockStreamManagementScope) ReleaseMemory(arg0 int) {
 }
 
 // ReleaseMemory indicates an expected call of ReleaseMemory.
-func (mr *MockStreamManagementScopeMockRecorder) ReleaseMemory(arg0 interface{}) *gomock.Call {
+func (mr *MockStreamManagementScopeMockRecorder) ReleaseMemory(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseMemory", reflect.TypeOf((*MockStreamManagementScope)(nil).ReleaseMemory), arg0)
 }
@@ -111,7 +115,7 @@ func (m *MockStreamManagementScope) ReserveMemory(arg0 int, arg1 byte) error {
 }
 
 // ReserveMemory indicates an expected call of ReserveMemory.
-func (mr *MockStreamManagementScopeMockRecorder) ReserveMemory(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockStreamManagementScopeMockRecorder) ReserveMemory(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReserveMemory", reflect.TypeOf((*MockStreamManagementScope)(nil).ReserveMemory), arg0, arg1)
 }
@@ -139,7 +143,7 @@ func (m *MockStreamManagementScope) SetProtocol(arg0 protocol.ID) error {
 }
 
 // SetProtocol indicates an expected call of SetProtocol.
-func (mr *MockStreamManagementScopeMockRecorder) SetProtocol(arg0 interface{}) *gomock.Call {
+func (mr *MockStreamManagementScopeMockRecorder) SetProtocol(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProtocol", reflect.TypeOf((*MockStreamManagementScope)(nil).SetProtocol), arg0)
 }
@@ -153,7 +157,7 @@ func (m *MockStreamManagementScope) SetService(arg0 string) error {
 }
 
 // SetService indicates an expected call of SetService.
-func (mr *MockStreamManagementScopeMockRecorder) SetService(arg0 interface{}) *gomock.Call {
+func (mr *MockStreamManagementScopeMockRecorder) SetService(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetService", reflect.TypeOf((*MockStreamManagementScope)(nil).SetService), arg0)
 }
diff --git a/go.mod b/go.mod
index 591a2990..23257e6c 100644
--- a/go.mod
+++ b/go.mod
@@ -57,7 +57,7 @@ require (
 	github.com/stretchr/testify v1.8.4
 	go.uber.org/fx v1.20.0
 	go.uber.org/goleak v1.2.0
-	go.uber.org/mock v0.2.0
+	go.uber.org/mock v0.3.0
 	go.uber.org/zap v1.25.0
 	golang.org/x/crypto v0.12.0
 	golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
diff --git a/go.sum b/go.sum
index 950eb1f0..f414930a 100644
--- a/go.sum
+++ b/go.sum
@@ -573,8 +573,8 @@ go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
 go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
-go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
-go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
+go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
+go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
diff --git a/p2p/host/resource-manager/extapi.go b/p2p/host/resource-manager/extapi.go
index 03edcd79..b3214f81 100644
--- a/p2p/host/resource-manager/extapi.go
+++ b/p2p/host/resource-manager/extapi.go
@@ -145,3 +145,7 @@ func (r *resourceManager) Stat() (result ResourceManagerStat) {
 
 	return result
 }
+
+func (r *resourceManager) GetConnLimit() int {
+	return r.limits.GetConnLimits().GetConnTotalLimit()
+}
diff --git a/p2p/net/connmgr/connmgr.go b/p2p/net/connmgr/connmgr.go
index b42a122f..6caa3dc1 100644
--- a/p2p/net/connmgr/connmgr.go
+++ b/p2p/net/connmgr/connmgr.go
@@ -2,6 +2,7 @@ package connmgr
 
 import (
 	"context"
+	"fmt"
 	"sort"
 	"sync"
 	"sync/atomic"
@@ -239,6 +240,17 @@ func (cm *BasicConnMgr) IsProtected(id peer.ID, tag string) (protected bool) {
 	return protected
 }
 
+func (cm *BasicConnMgr) CheckLimit(systemLimit connmgr.GetConnLimiter) error {
+	if cm.cfg.highWater > systemLimit.GetConnLimit() {
+		return fmt.Errorf(
+			"conn manager high watermark limit: %d, exceeds the system connection limit of: %d",
+			cm.cfg.highWater,
+			systemLimit.GetConnLimit(),
+		)
+	}
+	return nil
+}
+
 // peerInfo stores metadata for a given peer.
 type peerInfo struct {
 	id       peer.ID
diff --git a/p2p/transport/webrtc/stream.go b/p2p/transport/webrtc/stream.go
index 7e873f56..0358dce5 100644
--- a/p2p/transport/webrtc/stream.go
+++ b/p2p/transport/webrtc/stream.go
@@ -123,7 +123,23 @@ func newStream(
 			}
 		}
 
-		s.maybeDeclareStreamDone()
+		if s.isDone() {
+			// onDone removes the stream from the connection and requires the connection lock.
+			// This callback(onBufferedAmountLow) is executing in the sctp readLoop goroutine.
+			// If Connection.Close is called concurrently, the closing goroutine will acquire
+			// the connection lock and wait for sctp readLoop to exit, the sctp readLoop will
+			// wait for the connection lock before exiting, causing a deadlock.
+			// Run this in a different goroutine to avoid the deadlock.
+			go func() {
+				s.mx.Lock()
+				defer s.mx.Unlock()
+				// TODO: we should be closing the underlying datachannel, but this resets the stream
+				// See https://github.com/libp2p/specs/issues/575 for details.
+				// _ = s.dataChannel.Close()
+				// TODO: write for the spawned reader to return
+				s.onDone()
+			}()
+		}
 
 		select {
 		case s.writeAvailable <- struct{}{}:
@@ -186,11 +202,10 @@ func (s *stream) processIncomingFlag(flag *pb.Message_Flag) {
 	s.maybeDeclareStreamDone()
 }
 
-// this is used to force reset a stream
+// maybeDeclareStreamDone is used to force reset a stream. It should be called with
+// the stream lock acquired. It calls stream.onDone which requires the connection lock.
 func (s *stream) maybeDeclareStreamDone() {
-	if (s.sendState == sendStateReset || s.sendState == sendStateDataSent) &&
-		(s.receiveState == receiveStateReset || s.receiveState == receiveStateDataRead) &&
-		len(s.controlMsgQueue) == 0 {
+	if s.isDone() {
 		_ = s.SetReadDeadline(time.Now().Add(-1 * time.Hour)) // pion ignores zero times
 		// TODO: we should be closing the underlying datachannel, but this resets the stream
 		// See https://github.com/libp2p/specs/issues/575 for details.
@@ -200,6 +215,14 @@ func (s *stream) maybeDeclareStreamDone() {
 	}
 }
 
+// isDone indicates whether the stream is completed and all the control messages have also been
+// flushed. It must be called with the stream lock acquired.
+func (s *stream) isDone() bool {
+	return (s.sendState == sendStateReset || s.sendState == sendStateDataSent) &&
+		(s.receiveState == receiveStateReset || s.receiveState == receiveStateDataRead) &&
+		len(s.controlMsgQueue) == 0
+}
+
 func (s *stream) setCloseError(e error) {
 	s.mx.Lock()
 	defer s.mx.Unlock()
diff --git a/p2p/transport/webrtc/stream_write.go b/p2p/transport/webrtc/stream_write.go
index c7eb3bf7..698af9c4 100644
--- a/p2p/transport/webrtc/stream_write.go
+++ b/p2p/transport/webrtc/stream_write.go
@@ -35,6 +35,10 @@ func (s *stream) Write(b []byte) (int, error) {
 		s.readLoopOnce.Do(s.spawnControlMessageReader)
 	}
 
+	if !s.writeDeadline.IsZero() && time.Now().After(s.writeDeadline) {
+		return 0, os.ErrDeadlineExceeded
+	}
+
 	var writeDeadlineTimer *time.Timer
 	defer func() {
 		if writeDeadlineTimer != nil {
diff --git a/p2p/transport/webrtc/udpmux/muxed_connection.go b/p2p/transport/webrtc/udpmux/muxed_connection.go
index 202e0cae..5d86912a 100644
--- a/p2p/transport/webrtc/udpmux/muxed_connection.go
+++ b/p2p/transport/webrtc/udpmux/muxed_connection.go
@@ -5,6 +5,8 @@ import (
 	"errors"
 	"net"
 	"time"
+
+	pool "github.com/libp2p/go-buffer-pool"
 )
 
 var _ net.PacketConn = &muxedConnection{}
@@ -59,6 +61,7 @@ func (c *muxedConnection) ReadFrom(p []byte) (int, net.Addr, error) {
 		if n < len(buf) {
 			log.Debugf("short read, had %d, read %d", len(buf), n)
 		}
+		pool.Put(buf)
 		return n, c.remote, nil
 	case <-c.ctx.Done():
 		return 0, nil, c.ctx.Err()


Test patch:
diff --git a/p2p/host/basic/mock_nat_test.go b/p2p/host/basic/mock_nat_test.go
index 065f43e4..2fb9d9c8 100644
--- a/p2p/host/basic/mock_nat_test.go
+++ b/p2p/host/basic/mock_nat_test.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/p2p/host/basic (interfaces: NAT)
-
+//
+// Generated by this command:
+//
+//	mockgen -build_flags=-tags=gomock -package basichost -destination mock_nat_test.go github.com/libp2p/go-libp2p/p2p/host/basic NAT
+//
 // Package basichost is a generated GoMock package.
 package basichost
 
@@ -44,7 +48,7 @@ func (m *MockNAT) AddMapping(arg0 context.Context, arg1 string, arg2 int) error
 }
 
 // AddMapping indicates an expected call of AddMapping.
-func (mr *MockNATMockRecorder) AddMapping(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockNATMockRecorder) AddMapping(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMapping", reflect.TypeOf((*MockNAT)(nil).AddMapping), arg0, arg1, arg2)
 }
@@ -73,7 +77,7 @@ func (m *MockNAT) GetMapping(arg0 string, arg1 int) (netip.AddrPort, bool) {
 }
 
 // GetMapping indicates an expected call of GetMapping.
-func (mr *MockNATMockRecorder) GetMapping(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockNATMockRecorder) GetMapping(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMapping", reflect.TypeOf((*MockNAT)(nil).GetMapping), arg0, arg1)
 }
@@ -87,7 +91,7 @@ func (m *MockNAT) RemoveMapping(arg0 context.Context, arg1 string, arg2 int) err
 }
 
 // RemoveMapping indicates an expected call of RemoveMapping.
-func (mr *MockNATMockRecorder) RemoveMapping(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockNATMockRecorder) RemoveMapping(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveMapping", reflect.TypeOf((*MockNAT)(nil).RemoveMapping), arg0, arg1, arg2)
 }
diff --git a/p2p/host/pstoremanager/mock_peerstore_test.go b/p2p/host/pstoremanager/mock_peerstore_test.go
index 33dc760b..35c65f9e 100644
--- a/p2p/host/pstoremanager/mock_peerstore_test.go
+++ b/p2p/host/pstoremanager/mock_peerstore_test.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/peerstore (interfaces: Peerstore)
-
+//
+// Generated by this command:
+//
+//	mockgen -package pstoremanager_test -destination mock_peerstore_test.go github.com/libp2p/go-libp2p/core/peerstore Peerstore
+//
 // Package pstoremanager_test is a generated GoMock package.
 package pstoremanager_test
 
@@ -46,7 +50,7 @@ func (m *MockPeerstore) AddAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 tim
 }
 
 // AddAddr indicates an expected call of AddAddr.
-func (mr *MockPeerstoreMockRecorder) AddAddr(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) AddAddr(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAddr", reflect.TypeOf((*MockPeerstore)(nil).AddAddr), arg0, arg1, arg2)
 }
@@ -58,7 +62,7 @@ func (m *MockPeerstore) AddAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2
 }
 
 // AddAddrs indicates an expected call of AddAddrs.
-func (mr *MockPeerstoreMockRecorder) AddAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) AddAddrs(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAddrs", reflect.TypeOf((*MockPeerstore)(nil).AddAddrs), arg0, arg1, arg2)
 }
@@ -72,7 +76,7 @@ func (m *MockPeerstore) AddPrivKey(arg0 peer.ID, arg1 crypto.PrivKey) error {
 }
 
 // AddPrivKey indicates an expected call of AddPrivKey.
-func (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPrivKey", reflect.TypeOf((*MockPeerstore)(nil).AddPrivKey), arg0, arg1)
 }
@@ -80,7 +84,7 @@ func (mr *MockPeerstoreMockRecorder) AddPrivKey(arg0, arg1 interface{}) *gomock.
 // AddProtocols mocks base method.
 func (m *MockPeerstore) AddProtocols(arg0 peer.ID, arg1 ...protocol.ID) error {
 	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0}
+	varargs := []any{arg0}
 	for _, a := range arg1 {
 		varargs = append(varargs, a)
 	}
@@ -90,9 +94,9 @@ func (m *MockPeerstore) AddProtocols(arg0 peer.ID, arg1 ...protocol.ID) error {
 }
 
 // AddProtocols indicates an expected call of AddProtocols.
-func (mr *MockPeerstoreMockRecorder) AddProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) AddProtocols(arg0 any, arg1 ...any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0}, arg1...)
+	varargs := append([]any{arg0}, arg1...)
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddProtocols", reflect.TypeOf((*MockPeerstore)(nil).AddProtocols), varargs...)
 }
 
@@ -105,7 +109,7 @@ func (m *MockPeerstore) AddPubKey(arg0 peer.ID, arg1 crypto.PubKey) error {
 }
 
 // AddPubKey indicates an expected call of AddPubKey.
-func (mr *MockPeerstoreMockRecorder) AddPubKey(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) AddPubKey(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPubKey", reflect.TypeOf((*MockPeerstore)(nil).AddPubKey), arg0, arg1)
 }
@@ -119,7 +123,7 @@ func (m *MockPeerstore) AddrStream(arg0 context.Context, arg1 peer.ID) <-chan mu
 }
 
 // AddrStream indicates an expected call of AddrStream.
-func (mr *MockPeerstoreMockRecorder) AddrStream(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) AddrStream(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrStream", reflect.TypeOf((*MockPeerstore)(nil).AddrStream), arg0, arg1)
 }
@@ -133,7 +137,7 @@ func (m *MockPeerstore) Addrs(arg0 peer.ID) []multiaddr.Multiaddr {
 }
 
 // Addrs indicates an expected call of Addrs.
-func (mr *MockPeerstoreMockRecorder) Addrs(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) Addrs(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Addrs", reflect.TypeOf((*MockPeerstore)(nil).Addrs), arg0)
 }
@@ -145,7 +149,7 @@ func (m *MockPeerstore) ClearAddrs(arg0 peer.ID) {
 }
 
 // ClearAddrs indicates an expected call of ClearAddrs.
-func (mr *MockPeerstoreMockRecorder) ClearAddrs(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) ClearAddrs(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearAddrs", reflect.TypeOf((*MockPeerstore)(nil).ClearAddrs), arg0)
 }
@@ -167,7 +171,7 @@ func (mr *MockPeerstoreMockRecorder) Close() *gomock.Call {
 // FirstSupportedProtocol mocks base method.
 func (m *MockPeerstore) FirstSupportedProtocol(arg0 peer.ID, arg1 ...protocol.ID) (protocol.ID, error) {
 	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0}
+	varargs := []any{arg0}
 	for _, a := range arg1 {
 		varargs = append(varargs, a)
 	}
@@ -178,23 +182,23 @@ func (m *MockPeerstore) FirstSupportedProtocol(arg0 peer.ID, arg1 ...protocol.ID
 }
 
 // FirstSupportedProtocol indicates an expected call of FirstSupportedProtocol.
-func (mr *MockPeerstoreMockRecorder) FirstSupportedProtocol(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) FirstSupportedProtocol(arg0 any, arg1 ...any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0}, arg1...)
+	varargs := append([]any{arg0}, arg1...)
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSupportedProtocol", reflect.TypeOf((*MockPeerstore)(nil).FirstSupportedProtocol), varargs...)
 }
 
 // Get mocks base method.
-func (m *MockPeerstore) Get(arg0 peer.ID, arg1 string) (interface{}, error) {
+func (m *MockPeerstore) Get(arg0 peer.ID, arg1 string) (any, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Get", arg0, arg1)
-	ret0, _ := ret[0].(interface{})
+	ret0, _ := ret[0].(any)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // Get indicates an expected call of Get.
-func (mr *MockPeerstoreMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) Get(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockPeerstore)(nil).Get), arg0, arg1)
 }
@@ -209,7 +213,7 @@ func (m *MockPeerstore) GetProtocols(arg0 peer.ID) ([]protocol.ID, error) {
 }
 
 // GetProtocols indicates an expected call of GetProtocols.
-func (mr *MockPeerstoreMockRecorder) GetProtocols(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) GetProtocols(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProtocols", reflect.TypeOf((*MockPeerstore)(nil).GetProtocols), arg0)
 }
@@ -223,7 +227,7 @@ func (m *MockPeerstore) LatencyEWMA(arg0 peer.ID) time.Duration {
 }
 
 // LatencyEWMA indicates an expected call of LatencyEWMA.
-func (mr *MockPeerstoreMockRecorder) LatencyEWMA(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) LatencyEWMA(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatencyEWMA", reflect.TypeOf((*MockPeerstore)(nil).LatencyEWMA), arg0)
 }
@@ -237,7 +241,7 @@ func (m *MockPeerstore) PeerInfo(arg0 peer.ID) peer.AddrInfo {
 }
 
 // PeerInfo indicates an expected call of PeerInfo.
-func (mr *MockPeerstoreMockRecorder) PeerInfo(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) PeerInfo(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PeerInfo", reflect.TypeOf((*MockPeerstore)(nil).PeerInfo), arg0)
 }
@@ -293,7 +297,7 @@ func (m *MockPeerstore) PrivKey(arg0 peer.ID) crypto.PrivKey {
 }
 
 // PrivKey indicates an expected call of PrivKey.
-func (mr *MockPeerstoreMockRecorder) PrivKey(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) PrivKey(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrivKey", reflect.TypeOf((*MockPeerstore)(nil).PrivKey), arg0)
 }
@@ -307,13 +311,13 @@ func (m *MockPeerstore) PubKey(arg0 peer.ID) crypto.PubKey {
 }
 
 // PubKey indicates an expected call of PubKey.
-func (mr *MockPeerstoreMockRecorder) PubKey(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) PubKey(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PubKey", reflect.TypeOf((*MockPeerstore)(nil).PubKey), arg0)
 }
 
 // Put mocks base method.
-func (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 interface{}) error {
+func (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 any) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Put", arg0, arg1, arg2)
 	ret0, _ := ret[0].(error)
@@ -321,7 +325,7 @@ func (m *MockPeerstore) Put(arg0 peer.ID, arg1 string, arg2 interface{}) error {
 }
 
 // Put indicates an expected call of Put.
-func (mr *MockPeerstoreMockRecorder) Put(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) Put(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockPeerstore)(nil).Put), arg0, arg1, arg2)
 }
@@ -333,7 +337,7 @@ func (m *MockPeerstore) RecordLatency(arg0 peer.ID, arg1 time.Duration) {
 }
 
 // RecordLatency indicates an expected call of RecordLatency.
-func (mr *MockPeerstoreMockRecorder) RecordLatency(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) RecordLatency(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordLatency", reflect.TypeOf((*MockPeerstore)(nil).RecordLatency), arg0, arg1)
 }
@@ -345,7 +349,7 @@ func (m *MockPeerstore) RemovePeer(arg0 peer.ID) {
 }
 
 // RemovePeer indicates an expected call of RemovePeer.
-func (mr *MockPeerstoreMockRecorder) RemovePeer(arg0 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) RemovePeer(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePeer", reflect.TypeOf((*MockPeerstore)(nil).RemovePeer), arg0)
 }
@@ -353,7 +357,7 @@ func (mr *MockPeerstoreMockRecorder) RemovePeer(arg0 interface{}) *gomock.Call {
 // RemoveProtocols mocks base method.
 func (m *MockPeerstore) RemoveProtocols(arg0 peer.ID, arg1 ...protocol.ID) error {
 	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0}
+	varargs := []any{arg0}
 	for _, a := range arg1 {
 		varargs = append(varargs, a)
 	}
@@ -363,9 +367,9 @@ func (m *MockPeerstore) RemoveProtocols(arg0 peer.ID, arg1 ...protocol.ID) error
 }
 
 // RemoveProtocols indicates an expected call of RemoveProtocols.
-func (mr *MockPeerstoreMockRecorder) RemoveProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) RemoveProtocols(arg0 any, arg1 ...any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0}, arg1...)
+	varargs := append([]any{arg0}, arg1...)
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveProtocols", reflect.TypeOf((*MockPeerstore)(nil).RemoveProtocols), varargs...)
 }
 
@@ -376,7 +380,7 @@ func (m *MockPeerstore) SetAddr(arg0 peer.ID, arg1 multiaddr.Multiaddr, arg2 tim
 }
 
 // SetAddr indicates an expected call of SetAddr.
-func (mr *MockPeerstoreMockRecorder) SetAddr(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) SetAddr(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAddr", reflect.TypeOf((*MockPeerstore)(nil).SetAddr), arg0, arg1, arg2)
 }
@@ -388,7 +392,7 @@ func (m *MockPeerstore) SetAddrs(arg0 peer.ID, arg1 []multiaddr.Multiaddr, arg2
 }
 
 // SetAddrs indicates an expected call of SetAddrs.
-func (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAddrs", reflect.TypeOf((*MockPeerstore)(nil).SetAddrs), arg0, arg1, arg2)
 }
@@ -396,7 +400,7 @@ func (mr *MockPeerstoreMockRecorder) SetAddrs(arg0, arg1, arg2 interface{}) *gom
 // SetProtocols mocks base method.
 func (m *MockPeerstore) SetProtocols(arg0 peer.ID, arg1 ...protocol.ID) error {
 	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0}
+	varargs := []any{arg0}
 	for _, a := range arg1 {
 		varargs = append(varargs, a)
 	}
@@ -406,16 +410,16 @@ func (m *MockPeerstore) SetProtocols(arg0 peer.ID, arg1 ...protocol.ID) error {
 }
 
 // SetProtocols indicates an expected call of SetProtocols.
-func (mr *MockPeerstoreMockRecorder) SetProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) SetProtocols(arg0 any, arg1 ...any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0}, arg1...)
+	varargs := append([]any{arg0}, arg1...)
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProtocols", reflect.TypeOf((*MockPeerstore)(nil).SetProtocols), varargs...)
 }
 
 // SupportsProtocols mocks base method.
 func (m *MockPeerstore) SupportsProtocols(arg0 peer.ID, arg1 ...protocol.ID) ([]protocol.ID, error) {
 	m.ctrl.T.Helper()
-	varargs := []interface{}{arg0}
+	varargs := []any{arg0}
 	for _, a := range arg1 {
 		varargs = append(varargs, a)
 	}
@@ -426,9 +430,9 @@ func (m *MockPeerstore) SupportsProtocols(arg0 peer.ID, arg1 ...protocol.ID) ([]
 }
 
 // SupportsProtocols indicates an expected call of SupportsProtocols.
-func (mr *MockPeerstoreMockRecorder) SupportsProtocols(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) SupportsProtocols(arg0 any, arg1 ...any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	varargs := append([]interface{}{arg0}, arg1...)
+	varargs := append([]any{arg0}, arg1...)
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SupportsProtocols", reflect.TypeOf((*MockPeerstore)(nil).SupportsProtocols), varargs...)
 }
 
@@ -439,7 +443,7 @@ func (m *MockPeerstore) UpdateAddrs(arg0 peer.ID, arg1, arg2 time.Duration) {
 }
 
 // UpdateAddrs indicates an expected call of UpdateAddrs.
-func (mr *MockPeerstoreMockRecorder) UpdateAddrs(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockPeerstoreMockRecorder) UpdateAddrs(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAddrs", reflect.TypeOf((*MockPeerstore)(nil).UpdateAddrs), arg0, arg1, arg2)
 }
diff --git a/p2p/net/connmgr/connmgr_test.go b/p2p/net/connmgr/connmgr_test.go
index 8b5bbad4..3c2813e5 100644
--- a/p2p/net/connmgr/connmgr_test.go
+++ b/p2p/net/connmgr/connmgr_test.go
@@ -966,3 +966,24 @@ func TestSafeConcurrency(t *testing.T) {
 		wg.Wait()
 	})
 }
+
+func TestCheckLimit(t *testing.T) {
+	low, hi := 1, 2
+	cm, err := NewConnManager(low, hi)
+	require.NoError(t, err)
+
+	err = cm.CheckLimit(testLimitGetter{hi + 1})
+	require.NoError(t, err)
+	err = cm.CheckLimit(testLimitGetter{hi})
+	require.NoError(t, err)
+	err = cm.CheckLimit(testLimitGetter{hi - 1})
+	require.Error(t, err)
+}
+
+type testLimitGetter struct {
+	limit int
+}
+
+func (g testLimitGetter) GetConnLimit() int {
+	return g.limit
+}
diff --git a/p2p/net/nat/mock_nat_test.go b/p2p/net/nat/mock_nat_test.go
index f01164bf..d0005723 100644
--- a/p2p/net/nat/mock_nat_test.go
+++ b/p2p/net/nat/mock_nat_test.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-nat (interfaces: NAT)
-
+//
+// Generated by this command:
+//
+//	mockgen -package nat -destination mock_nat_test.go github.com/libp2p/go-nat NAT
+//
 // Package nat is a generated GoMock package.
 package nat
 
@@ -46,7 +50,7 @@ func (m *MockNAT) AddPortMapping(arg0 context.Context, arg1 string, arg2 int, ar
 }
 
 // AddPortMapping indicates an expected call of AddPortMapping.
-func (mr *MockNATMockRecorder) AddPortMapping(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
+func (mr *MockNATMockRecorder) AddPortMapping(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddPortMapping", reflect.TypeOf((*MockNAT)(nil).AddPortMapping), arg0, arg1, arg2, arg3, arg4)
 }
@@ -60,7 +64,7 @@ func (m *MockNAT) DeletePortMapping(arg0 context.Context, arg1 string, arg2 int)
 }
 
 // DeletePortMapping indicates an expected call of DeletePortMapping.
-func (mr *MockNATMockRecorder) DeletePortMapping(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockNATMockRecorder) DeletePortMapping(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePortMapping", reflect.TypeOf((*MockNAT)(nil).DeletePortMapping), arg0, arg1, arg2)
 }
diff --git a/p2p/test/transport/mock_connection_gater_test.go b/p2p/test/transport/mock_connection_gater_test.go
index f7f4c1a7..ff7cffdd 100644
--- a/p2p/test/transport/mock_connection_gater_test.go
+++ b/p2p/test/transport/mock_connection_gater_test.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/connmgr (interfaces: ConnectionGater)
-
+//
+// Generated by this command:
+//
+//	mockgen -package transport_integration -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater
+//
 // Package transport_integration is a generated GoMock package.
 package transport_integration
 
@@ -46,7 +50,7 @@ func (m *MockConnectionGater) InterceptAccept(arg0 network.ConnMultiaddrs) bool
 }
 
 // InterceptAccept indicates an expected call of InterceptAccept.
-func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAccept", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAccept), arg0)
 }
@@ -60,7 +64,7 @@ func (m *MockConnectionGater) InterceptAddrDial(arg0 peer.ID, arg1 multiaddr.Mul
 }
 
 // InterceptAddrDial indicates an expected call of InterceptAddrDial.
-func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAddrDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAddrDial), arg0, arg1)
 }
@@ -74,7 +78,7 @@ func (m *MockConnectionGater) InterceptPeerDial(arg0 peer.ID) bool {
 }
 
 // InterceptPeerDial indicates an expected call of InterceptPeerDial.
-func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptPeerDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptPeerDial), arg0)
 }
@@ -88,7 +92,7 @@ func (m *MockConnectionGater) InterceptSecured(arg0 network.Direction, arg1 peer
 }
 
 // InterceptSecured indicates an expected call of InterceptSecured.
-func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptSecured", reflect.TypeOf((*MockConnectionGater)(nil).InterceptSecured), arg0, arg1, arg2)
 }
@@ -103,7 +107,7 @@ func (m *MockConnectionGater) InterceptUpgraded(arg0 network.Conn) (bool, contro
 }
 
 // InterceptUpgraded indicates an expected call of InterceptUpgraded.
-func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptUpgraded", reflect.TypeOf((*MockConnectionGater)(nil).InterceptUpgraded), arg0)
 }
diff --git a/p2p/transport/quic/mock_connection_gater_test.go b/p2p/transport/quic/mock_connection_gater_test.go
index cbea666d..a445e2e1 100644
--- a/p2p/transport/quic/mock_connection_gater_test.go
+++ b/p2p/transport/quic/mock_connection_gater_test.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/connmgr (interfaces: ConnectionGater)
-
+//
+// Generated by this command:
+//
+//	mockgen -package libp2pquic -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater
+//
 // Package libp2pquic is a generated GoMock package.
 package libp2pquic
 
@@ -46,7 +50,7 @@ func (m *MockConnectionGater) InterceptAccept(arg0 network.ConnMultiaddrs) bool
 }
 
 // InterceptAccept indicates an expected call of InterceptAccept.
-func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAccept", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAccept), arg0)
 }
@@ -60,7 +64,7 @@ func (m *MockConnectionGater) InterceptAddrDial(arg0 peer.ID, arg1 multiaddr.Mul
 }
 
 // InterceptAddrDial indicates an expected call of InterceptAddrDial.
-func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAddrDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAddrDial), arg0, arg1)
 }
@@ -74,7 +78,7 @@ func (m *MockConnectionGater) InterceptPeerDial(arg0 peer.ID) bool {
 }
 
 // InterceptPeerDial indicates an expected call of InterceptPeerDial.
-func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptPeerDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptPeerDial), arg0)
 }
@@ -88,7 +92,7 @@ func (m *MockConnectionGater) InterceptSecured(arg0 network.Direction, arg1 peer
 }
 
 // InterceptSecured indicates an expected call of InterceptSecured.
-func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptSecured", reflect.TypeOf((*MockConnectionGater)(nil).InterceptSecured), arg0, arg1, arg2)
 }
@@ -103,7 +107,7 @@ func (m *MockConnectionGater) InterceptUpgraded(arg0 network.Conn) (bool, contro
 }
 
 // InterceptUpgraded indicates an expected call of InterceptUpgraded.
-func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptUpgraded", reflect.TypeOf((*MockConnectionGater)(nil).InterceptUpgraded), arg0)
 }
diff --git a/p2p/transport/webrtc/transport_test.go b/p2p/transport/webrtc/transport_test.go
index 19d39ba2..7f4df94f 100644
--- a/p2p/transport/webrtc/transport_test.go
+++ b/p2p/transport/webrtc/transport_test.go
@@ -402,10 +402,16 @@ func TestTransportWebRTC_Deadline(t *testing.T) {
 		stream, err := conn.OpenStream(context.Background())
 		require.NoError(t, err)
 
-		stream.SetWriteDeadline(time.Now().Add(200 * time.Millisecond))
+		stream.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
 		largeBuffer := make([]byte, 2*1024*1024)
 		_, err = stream.Write(largeBuffer)
 		require.ErrorIs(t, err, os.ErrDeadlineExceeded)
+
+		stream.SetWriteDeadline(time.Now().Add(-200 * time.Millisecond))
+		smallBuffer := make([]byte, 1024)
+		_, err = stream.Write(smallBuffer)
+		require.ErrorIs(t, err, os.ErrDeadlineExceeded)
+
 	})
 }
 
diff --git a/p2p/transport/webtransport/mock_connection_gater_test.go b/p2p/transport/webtransport/mock_connection_gater_test.go
index 1b74bfe5..2c42cd25 100644
--- a/p2p/transport/webtransport/mock_connection_gater_test.go
+++ b/p2p/transport/webtransport/mock_connection_gater_test.go
@@ -1,6 +1,10 @@
 // Code generated by MockGen. DO NOT EDIT.
 // Source: github.com/libp2p/go-libp2p/core/connmgr (interfaces: ConnectionGater)
-
+//
+// Generated by this command:
+//
+//	mockgen -package libp2pwebtransport_test -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater
+//
 // Package libp2pwebtransport_test is a generated GoMock package.
 package libp2pwebtransport_test
 
@@ -46,7 +50,7 @@ func (m *MockConnectionGater) InterceptAccept(arg0 network.ConnMultiaddrs) bool
 }
 
 // InterceptAccept indicates an expected call of InterceptAccept.
-func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptAccept(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAccept", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAccept), arg0)
 }
@@ -60,7 +64,7 @@ func (m *MockConnectionGater) InterceptAddrDial(arg0 peer.ID, arg1 multiaddr.Mul
 }
 
 // InterceptAddrDial indicates an expected call of InterceptAddrDial.
-func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptAddrDial(arg0, arg1 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptAddrDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptAddrDial), arg0, arg1)
 }
@@ -74,7 +78,7 @@ func (m *MockConnectionGater) InterceptPeerDial(arg0 peer.ID) bool {
 }
 
 // InterceptPeerDial indicates an expected call of InterceptPeerDial.
-func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptPeerDial(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptPeerDial", reflect.TypeOf((*MockConnectionGater)(nil).InterceptPeerDial), arg0)
 }
@@ -88,7 +92,7 @@ func (m *MockConnectionGater) InterceptSecured(arg0 network.Direction, arg1 peer
 }
 
 // InterceptSecured indicates an expected call of InterceptSecured.
-func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptSecured(arg0, arg1, arg2 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptSecured", reflect.TypeOf((*MockConnectionGater)(nil).InterceptSecured), arg0, arg1, arg2)
 }
@@ -103,7 +107,7 @@ func (m *MockConnectionGater) InterceptUpgraded(arg0 network.Conn) (bool, contro
 }
 
 // InterceptUpgraded indicates an expected call of InterceptUpgraded.
-func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 interface{}) *gomock.Call {
+func (mr *MockConnectionGaterMockRecorder) InterceptUpgraded(arg0 any) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InterceptUpgraded", reflect.TypeOf((*MockConnectionGater)(nil).InterceptUpgraded), arg0)
 }
diff --git a/test-plans/go.mod b/test-plans/go.mod
index 94322936..cb59c98a 100644
--- a/test-plans/go.mod
+++ b/test-plans/go.mod
@@ -111,7 +111,7 @@ require (
 	github.com/stretchr/testify v1.8.4 // indirect
 	go.uber.org/dig v1.17.0 // indirect
 	go.uber.org/fx v1.20.0 // indirect
-	go.uber.org/mock v0.2.0 // indirect
+	go.uber.org/mock v0.3.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.25.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/test-plans/go.sum b/test-plans/go.sum
index 86d48e2b..9caad82b 100644
--- a/test-plans/go.sum
+++ b/test-plans/go.sum
@@ -374,8 +374,8 @@ go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ=
 go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
-go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
-go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
+go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
+go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=