diff --git a/internal/ackhandler/sent_packet_handler.go b/internal/ackhandler/sent_packet_handler.go index c586495e..4b6ab14c 100644 --- a/internal/ackhandler/sent_packet_handler.go +++ b/internal/ackhandler/sent_packet_handler.go @@ -56,7 +56,7 @@ type sentPacketHandler struct { bytesInFlight protocol.ByteCount - congestion congestion.SendAlgorithm + congestion congestion.SendAlgorithmWithDebugInfos rttStats *congestion.RTTStats handshakeComplete bool @@ -552,9 +552,9 @@ func (h *sentPacketHandler) SendMode() SendMode { return SendPTO } // Only send ACKs if we're congestion limited. - if cwnd := h.congestion.GetCongestionWindow(); h.bytesInFlight > cwnd { + if !h.congestion.CanSend(h.bytesInFlight) { if h.logger.Debug() { - h.logger.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, cwnd) + h.logger.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, h.congestion.GetCongestionWindow()) } return SendAck } diff --git a/internal/ackhandler/sent_packet_handler_test.go b/internal/ackhandler/sent_packet_handler_test.go index 0b0477b2..1697691e 100644 --- a/internal/ackhandler/sent_packet_handler_test.go +++ b/internal/ackhandler/sent_packet_handler_test.go @@ -423,10 +423,10 @@ var _ = Describe("SentPacketHandler", func() { }) Context("congestion", func() { - var cong *mocks.MockSendAlgorithm + var cong *mocks.MockSendAlgorithmWithDebugInfos BeforeEach(func() { - cong = mocks.NewMockSendAlgorithm(mockCtrl) + cong = mocks.NewMockSendAlgorithmWithDebugInfos(mockCtrl) handler.congestion = cong }) @@ -511,16 +511,21 @@ var _ = Describe("SentPacketHandler", func() { Expect(err).ToNot(HaveOccurred()) }) - It("only allows sending of ACKs when congestion limited", func() { - handler.bytesInFlight = 100 - cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(200)) + It("passes the bytes in flight to CanSend", func() { + handler.bytesInFlight = 42 + cong.EXPECT().CanSend(protocol.ByteCount(42)) + handler.SendMode() + }) + + It("allows sending of ACKs when congestion limited", func() { + cong.EXPECT().CanSend(gomock.Any()).Return(true) Expect(handler.SendMode()).To(Equal(SendAny)) - cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(75)) + cong.EXPECT().CanSend(gomock.Any()).Return(false) Expect(handler.SendMode()).To(Equal(SendAck)) }) - It("only allows sending of ACKs when we're keeping track of MaxOutstandingSentPackets packets", func() { - cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount).AnyTimes() + It("allows sending of ACKs when we're keeping track of MaxOutstandingSentPackets packets", func() { + cong.EXPECT().CanSend(gomock.Any()).Return(true).AnyTimes() cong.EXPECT().TimeUntilSend(gomock.Any()).AnyTimes() cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() for i := protocol.PacketNumber(1); i < protocol.MaxOutstandingSentPackets; i++ { @@ -531,21 +536,20 @@ var _ = Describe("SentPacketHandler", func() { Expect(handler.SendMode()).To(Equal(SendAck)) }) - It("doesn't allow retransmission if congestion limited", func() { - handler.bytesInFlight = 100 + It("doesn't allow retransmissions if congestion limited", func() { handler.retransmissionQueue = []*Packet{{PacketNumber: 3}} - cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(50)) + cong.EXPECT().CanSend(gomock.Any()).Return(false) Expect(handler.SendMode()).To(Equal(SendAck)) }) It("allows sending retransmissions", func() { - cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount) + cong.EXPECT().CanSend(gomock.Any()).Return(true) handler.retransmissionQueue = []*Packet{{PacketNumber: 3}} Expect(handler.SendMode()).To(Equal(SendRetransmission)) }) - It("allow retransmissions, if we're keeping track of between MaxOutstandingSentPackets and MaxTrackedSentPackets packets", func() { - cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount) + It("allows retransmissions, if we're keeping track of between MaxOutstandingSentPackets and MaxTrackedSentPackets packets", func() { + cong.EXPECT().CanSend(gomock.Any()).Return(true) Expect(protocol.MaxOutstandingSentPackets).To(BeNumerically("<", protocol.MaxTrackedSentPackets)) handler.retransmissionQueue = make([]*Packet, protocol.MaxOutstandingSentPackets+10) Expect(handler.SendMode()).To(Equal(SendRetransmission)) diff --git a/internal/congestion/cubic_sender.go b/internal/congestion/cubic_sender.go index 2a45b354..d04ec1e4 100644 --- a/internal/congestion/cubic_sender.go +++ b/internal/congestion/cubic_sender.go @@ -63,6 +63,7 @@ type cubicSender struct { } var _ SendAlgorithm = &cubicSender{} +var _ SendAlgorithmWithDebugInfos = &cubicSender{} // NewCubicSender makes a new cubic sender func NewCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestionWindow, initialMaxCongestionWindow protocol.ByteCount) *cubicSender { @@ -112,6 +113,13 @@ func (c *cubicSender) OnPacketSent( c.hybridSlowStart.OnPacketSent(packetNumber) } +func (c *cubicSender) CanSend(bytesInFlight protocol.ByteCount) bool { + if c.InRecovery() { + return c.prr.CanSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold()) + } + return bytesInFlight < c.GetCongestionWindow() +} + func (c *cubicSender) InRecovery() bool { return c.largestAckedPacketNumber != protocol.InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback } diff --git a/internal/congestion/cubic_sender_test.go b/internal/congestion/cubic_sender_test.go index 1f1357df..2c02216e 100644 --- a/internal/congestion/cubic_sender_test.go +++ b/internal/congestion/cubic_sender_test.go @@ -43,13 +43,9 @@ var _ = Describe("Cubic Sender", func() { sender = NewCubicSender(&clock, rttStats, true /*reno*/, initialCongestionWindowPackets*protocol.DefaultTCPMSS, MaxCongestionWindow) }) - canSend := func() bool { - return bytesInFlight < sender.GetCongestionWindow() - } - SendAvailableSendWindowLen := func(packetLength protocol.ByteCount) int { packetsSent := 0 - for canSend() { + for sender.CanSend(bytesInFlight) { sender.OnPacketSent(clock.Now(), bytesInFlight, packetNumber, packetLength, true) packetNumber++ packetsSent++ @@ -92,13 +88,13 @@ var _ = Describe("Cubic Sender", func() { Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) // Make sure we can send. Expect(sender.TimeUntilSend(0)).To(BeZero()) - Expect(canSend()).To(BeTrue()) + Expect(sender.CanSend(bytesInFlight)).To(BeTrue()) // And that window is un-affected. Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP)) // Fill the send window with data, then verify that we can't send. SendAvailableSendWindow() - Expect(canSend()).To(BeFalse()) + Expect(sender.CanSend(bytesInFlight)).To(BeFalse()) }) It("paces", func() { @@ -115,8 +111,7 @@ var _ = Describe("Cubic Sender", func() { // Send exactly 10 packets and ensure the CWND ends at 14 packets. const numberOfAcks = 5 // At startup make sure we can send. - Expect(sender.TimeUntilSend(0)).To(BeZero()) - // Make sure we can send. + Expect(sender.CanSend(0)).To(BeTrue()) Expect(sender.TimeUntilSend(0)).To(BeZero()) SendAvailableSendWindow() @@ -132,6 +127,7 @@ var _ = Describe("Cubic Sender", func() { It("exponential slow start", func() { const numberOfAcks = 20 // At startup make sure we can send. + Expect(sender.CanSend(0)).To(BeTrue()) Expect(sender.TimeUntilSend(0)).To(BeZero()) Expect(sender.BandwidthEstimate()).To(BeZero()) // Make sure we can send. @@ -268,8 +264,7 @@ var _ = Describe("Cubic Sender", func() { Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) }) - // this test doesn't work any more after introducing the pacing needed for QUIC - PIt("no PRR when less than one packet in flight", func() { + It("no PRR when less than one packet in flight", func() { SendAvailableSendWindow() LoseNPackets(int(initialCongestionWindowPackets) - 1) AckNPackets(1) @@ -278,7 +273,7 @@ var _ = Describe("Cubic Sender", func() { // Simulate abandoning all packets by supplying a bytes_in_flight of 0. // PRR should now allow a packet to be sent, even though prr's state // variables believe it has sent enough packets. - Expect(sender.TimeUntilSend(0)).To(BeZero()) + Expect(sender.CanSend(0)).To(BeTrue()) }) It("slow start packet loss PRR", func() { @@ -351,7 +346,7 @@ var _ = Describe("Cubic Sender", func() { LoseNPackets(int(numPacketsToLose)) // Immediately after the loss, ensure at least one packet can be sent. // Losses without subsequent acks can occur with timer based loss detection. - Expect(sender.TimeUntilSend(bytesInFlight)).To(BeZero()) + Expect(sender.CanSend(bytesInFlight)).To(BeTrue()) AckNPackets(1) // We should now have fallen out of slow start with a reduced window. diff --git a/internal/congestion/interface.go b/internal/congestion/interface.go index cccbabbe..c6f09821 100644 --- a/internal/congestion/interface.go +++ b/internal/congestion/interface.go @@ -6,13 +6,19 @@ import ( "github.com/lucas-clemente/quic-go/internal/protocol" ) -// A SendAlgorithm performs congestion control and calculates the congestion window +// A SendAlgorithm performs congestion control type SendAlgorithm interface { TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool) - GetCongestionWindow() protocol.ByteCount + CanSend(bytesInFlight protocol.ByteCount) bool MaybeExitSlowStart() OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime time.Time) OnPacketLost(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount) OnRetransmissionTimeout(packetsRetransmitted bool) } + +// A SendAlgorithmWithDebugInfos is a SendAlgorithm that exposes some debug infos +type SendAlgorithmWithDebugInfos interface { + SendAlgorithm + GetCongestionWindow() protocol.ByteCount +} diff --git a/internal/mocks/congestion.go b/internal/mocks/congestion.go index b9866593..ea8970ff 100644 --- a/internal/mocks/congestion.go +++ b/internal/mocks/congestion.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/lucas-clemente/quic-go/internal/congestion (interfaces: SendAlgorithm) +// Source: github.com/lucas-clemente/quic-go/internal/congestion (interfaces: SendAlgorithmWithDebugInfos) // Package mocks is a generated GoMock package. package mocks @@ -12,31 +12,45 @@ import ( protocol "github.com/lucas-clemente/quic-go/internal/protocol" ) -// MockSendAlgorithm is a mock of SendAlgorithm interface -type MockSendAlgorithm struct { +// MockSendAlgorithmWithDebugInfos is a mock of SendAlgorithmWithDebugInfos interface +type MockSendAlgorithmWithDebugInfos struct { ctrl *gomock.Controller - recorder *MockSendAlgorithmMockRecorder + recorder *MockSendAlgorithmWithDebugInfosMockRecorder } -// MockSendAlgorithmMockRecorder is the mock recorder for MockSendAlgorithm -type MockSendAlgorithmMockRecorder struct { - mock *MockSendAlgorithm +// MockSendAlgorithmWithDebugInfosMockRecorder is the mock recorder for MockSendAlgorithmWithDebugInfos +type MockSendAlgorithmWithDebugInfosMockRecorder struct { + mock *MockSendAlgorithmWithDebugInfos } -// NewMockSendAlgorithm creates a new mock instance -func NewMockSendAlgorithm(ctrl *gomock.Controller) *MockSendAlgorithm { - mock := &MockSendAlgorithm{ctrl: ctrl} - mock.recorder = &MockSendAlgorithmMockRecorder{mock} +// NewMockSendAlgorithmWithDebugInfos creates a new mock instance +func NewMockSendAlgorithmWithDebugInfos(ctrl *gomock.Controller) *MockSendAlgorithmWithDebugInfos { + mock := &MockSendAlgorithmWithDebugInfos{ctrl: ctrl} + mock.recorder = &MockSendAlgorithmWithDebugInfosMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use -func (m *MockSendAlgorithm) EXPECT() *MockSendAlgorithmMockRecorder { +func (m *MockSendAlgorithmWithDebugInfos) EXPECT() *MockSendAlgorithmWithDebugInfosMockRecorder { return m.recorder } +// CanSend mocks base method +func (m *MockSendAlgorithmWithDebugInfos) CanSend(arg0 protocol.ByteCount) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CanSend", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// CanSend indicates an expected call of CanSend +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) CanSend(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSend", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).CanSend), arg0) +} + // GetCongestionWindow mocks base method -func (m *MockSendAlgorithm) GetCongestionWindow() protocol.ByteCount { +func (m *MockSendAlgorithmWithDebugInfos) GetCongestionWindow() protocol.ByteCount { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetCongestionWindow") ret0, _ := ret[0].(protocol.ByteCount) @@ -44,73 +58,73 @@ func (m *MockSendAlgorithm) GetCongestionWindow() protocol.ByteCount { } // GetCongestionWindow indicates an expected call of GetCongestionWindow -func (mr *MockSendAlgorithmMockRecorder) GetCongestionWindow() *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) GetCongestionWindow() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCongestionWindow", reflect.TypeOf((*MockSendAlgorithm)(nil).GetCongestionWindow)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCongestionWindow", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).GetCongestionWindow)) } // MaybeExitSlowStart mocks base method -func (m *MockSendAlgorithm) MaybeExitSlowStart() { +func (m *MockSendAlgorithmWithDebugInfos) MaybeExitSlowStart() { m.ctrl.T.Helper() m.ctrl.Call(m, "MaybeExitSlowStart") } // MaybeExitSlowStart indicates an expected call of MaybeExitSlowStart -func (mr *MockSendAlgorithmMockRecorder) MaybeExitSlowStart() *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) MaybeExitSlowStart() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybeExitSlowStart", reflect.TypeOf((*MockSendAlgorithm)(nil).MaybeExitSlowStart)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybeExitSlowStart", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).MaybeExitSlowStart)) } // OnPacketAcked mocks base method -func (m *MockSendAlgorithm) OnPacketAcked(arg0 protocol.PacketNumber, arg1, arg2 protocol.ByteCount, arg3 time.Time) { +func (m *MockSendAlgorithmWithDebugInfos) OnPacketAcked(arg0 protocol.PacketNumber, arg1, arg2 protocol.ByteCount, arg3 time.Time) { m.ctrl.T.Helper() m.ctrl.Call(m, "OnPacketAcked", arg0, arg1, arg2, arg3) } // OnPacketAcked indicates an expected call of OnPacketAcked -func (mr *MockSendAlgorithmMockRecorder) OnPacketAcked(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) OnPacketAcked(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketAcked", reflect.TypeOf((*MockSendAlgorithm)(nil).OnPacketAcked), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketAcked", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).OnPacketAcked), arg0, arg1, arg2, arg3) } // OnPacketLost mocks base method -func (m *MockSendAlgorithm) OnPacketLost(arg0 protocol.PacketNumber, arg1, arg2 protocol.ByteCount) { +func (m *MockSendAlgorithmWithDebugInfos) OnPacketLost(arg0 protocol.PacketNumber, arg1, arg2 protocol.ByteCount) { m.ctrl.T.Helper() m.ctrl.Call(m, "OnPacketLost", arg0, arg1, arg2) } // OnPacketLost indicates an expected call of OnPacketLost -func (mr *MockSendAlgorithmMockRecorder) OnPacketLost(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) OnPacketLost(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketLost", reflect.TypeOf((*MockSendAlgorithm)(nil).OnPacketLost), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketLost", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).OnPacketLost), arg0, arg1, arg2) } // OnPacketSent mocks base method -func (m *MockSendAlgorithm) OnPacketSent(arg0 time.Time, arg1 protocol.ByteCount, arg2 protocol.PacketNumber, arg3 protocol.ByteCount, arg4 bool) { +func (m *MockSendAlgorithmWithDebugInfos) OnPacketSent(arg0 time.Time, arg1 protocol.ByteCount, arg2 protocol.PacketNumber, arg3 protocol.ByteCount, arg4 bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "OnPacketSent", arg0, arg1, arg2, arg3, arg4) } // OnPacketSent indicates an expected call of OnPacketSent -func (mr *MockSendAlgorithmMockRecorder) OnPacketSent(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) OnPacketSent(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketSent", reflect.TypeOf((*MockSendAlgorithm)(nil).OnPacketSent), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnPacketSent", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).OnPacketSent), arg0, arg1, arg2, arg3, arg4) } // OnRetransmissionTimeout mocks base method -func (m *MockSendAlgorithm) OnRetransmissionTimeout(arg0 bool) { +func (m *MockSendAlgorithmWithDebugInfos) OnRetransmissionTimeout(arg0 bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "OnRetransmissionTimeout", arg0) } // OnRetransmissionTimeout indicates an expected call of OnRetransmissionTimeout -func (mr *MockSendAlgorithmMockRecorder) OnRetransmissionTimeout(arg0 interface{}) *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) OnRetransmissionTimeout(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRetransmissionTimeout", reflect.TypeOf((*MockSendAlgorithm)(nil).OnRetransmissionTimeout), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnRetransmissionTimeout", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).OnRetransmissionTimeout), arg0) } // TimeUntilSend mocks base method -func (m *MockSendAlgorithm) TimeUntilSend(arg0 protocol.ByteCount) time.Duration { +func (m *MockSendAlgorithmWithDebugInfos) TimeUntilSend(arg0 protocol.ByteCount) time.Duration { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TimeUntilSend", arg0) ret0, _ := ret[0].(time.Duration) @@ -118,7 +132,7 @@ func (m *MockSendAlgorithm) TimeUntilSend(arg0 protocol.ByteCount) time.Duration } // TimeUntilSend indicates an expected call of TimeUntilSend -func (mr *MockSendAlgorithmMockRecorder) TimeUntilSend(arg0 interface{}) *gomock.Call { +func (mr *MockSendAlgorithmWithDebugInfosMockRecorder) TimeUntilSend(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSendAlgorithm)(nil).TimeUntilSend), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSendAlgorithmWithDebugInfos)(nil).TimeUntilSend), arg0) } diff --git a/internal/mocks/mockgen.go b/internal/mocks/mockgen.go index 69348fb8..4fa465b1 100644 --- a/internal/mocks/mockgen.go +++ b/internal/mocks/mockgen.go @@ -8,5 +8,5 @@ package mocks //go:generate sh -c "../mockgen_internal.sh mocks stream_flow_controller.go github.com/lucas-clemente/quic-go/internal/flowcontrol StreamFlowController" //go:generate sh -c "../mockgen_internal.sh mockackhandler ackhandler/sent_packet_handler.go github.com/lucas-clemente/quic-go/internal/ackhandler SentPacketHandler" //go:generate sh -c "../mockgen_internal.sh mockackhandler ackhandler/received_packet_handler.go github.com/lucas-clemente/quic-go/internal/ackhandler ReceivedPacketHandler" -//go:generate sh -c "../mockgen_internal.sh mocks congestion.go github.com/lucas-clemente/quic-go/internal/congestion SendAlgorithm" +//go:generate sh -c "../mockgen_internal.sh mocks congestion.go github.com/lucas-clemente/quic-go/internal/congestion SendAlgorithmWithDebugInfos" //go:generate sh -c "../mockgen_internal.sh mocks connection_flow_controller.go github.com/lucas-clemente/quic-go/internal/flowcontrol ConnectionFlowController"