Commit Graph

2620 Commits

Author SHA1 Message Date
Matthias Einwag 8610179063 Derive pacing capacity from window and time
The pacer's behavior currently makes the library extremely inefficient.
Each `Pacer::delay` call would only allow a single
datagram to be sent, and then instruct the connection to wait a tiny
time-slice (which is far smaller than the timer granularity). When the timer
really elapses (e.g. a tokio timer after 1ms) only 1 packet can be sent
again.

This change improves on this by deriving the pacer capacity based on
how big bursts should be, and how much delay we want to have between
those. A pacer delay bigger than timer granularity is desirable for
efficiency and performance reasons. Here 2ms had been chosen, which
had proven effective in tests with an injected RTT.
2021-01-22 19:16:50 +01:00
Matthias Einwag 728fdb9b61 Reset pacing timer
The pacing implementation did so far not do anything. The reason for
that is the timestamp when tokens had been last generated was never
updated. Therefore each Pacer::delay call where not enough tokens
had been available calculated tokens based on the time back to when
the Pacer was initially created, which fully refills the capacity.

This is easily fixed by storing the timestamp when tokens are replenished.
2021-01-22 19:16:50 +01:00
Matthias Einwag 49e57a2f41 Use all tokens for pacing
There is no need for leaving the last token inside the bucket unused.
2021-01-22 19:16:50 +01:00
Matthias Einwag c07201d765 Use correct RTT for pacing
Pacing should make use of the more stable "smoothed" RTT instead
of the last observed RTT, to prevent sudden changes in packet emission.
2021-01-22 19:16:50 +01:00
Matthias Einwag bcbb58fe1b Fix StreamAssembler panic/underflow
The variable `defragmented` wasn't properly updated in the
`read_chunks` method, since it directly manipulated the map instead
of delegating to the `Assembler::pop` method. This caused an underflow
when trying to insert more data into the map.

This change fixes that, and adds a repro test for it.

Fixes #982
2021-01-22 08:01:47 +01:00
Matthias Einwag 4f8a5ebaf1 Non contiguous Send buffer
During testing with a multithreaded runtime I discovered that threads
block a fair amount of time on Mutexes, even though everything in the
state machine should be non-blocking.

By inserting some more timing checks I discovered that the `poll_write`
call took more than 10ms and locked the Mutex for this duration. This
happened due to the `BytesMut::extend_from_slice` taking this time.

The reason here is that extending the buffer require a reallocation of
the buffer and a copy of the complete data. This can be a big size
(up the maximum internal buffer size) - even if only a tiny chunk of
data is added.

This change improves on this by using a non-contiguous send buffer.
New data is appended as a new `Bytes` segment, which only requires
an allocation for this particular size. The 10ms blocking problem is
gone with this.

Another benefit of this change is that it can easily enable zero-copy
writes by accepting `Bytes` as a parameter in the user-facing API.
This is however not performed here yet.

```
Jan 18 11:14:00.064  WARN quinn_proto::connection::send_buffer: self.unacked.extend_from_slice(data[..1048576]) took 10.3452ms. Now unacked size: 94924462
Jan 18 11:14:00.064  WARN quinn_proto::connection::streams: Long Send::write. Total: 10.3943ms, Budget check: 0ns, data_len: 1048576, written: 1048576
Jan 18 11:14:00.064  WARN quinn_proto::connection::streams: Long Streams::write. Total: 10.4203ms, Limit check: 100ns, Unsent check: 200ns, Write: 10.4202ms. data_len: 1048576, written: 1048576
Jan 18 11:14:00.064  WARN quinn::streams: Long poll_write time: close_check 100ns, write_time 10.4456ms, end_time 10.4456ms
```
2021-01-20 09:38:27 +01:00
Matthias Einwag b2d09655c2 Ignore ACKs of data which is no longer tracked
If an a range is acknowledged where a part of it had been previously
acknowledged - ignore the acknowledged range. While the
retransmission logic guarantees this property at the moment, it
might not always hold true.
2021-01-20 09:38:27 +01:00
Matthias Einwag 6f1687c5fb Fix bulk benchmark
The sending data on the benchmark failed it panicked due
to an unwrap and thereby showed no result. This propagates
the first client-side error instead of panicking - which will also
preserve the statistics.
2021-01-19 08:16:47 +01:00
Timon Post 6faa5a3ba9 round 3 2021-01-18 09:30:32 +01:00
Timon f6f832687f Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon d13d9e9c66 Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon 4da254e7b8 Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon 1ff316178c Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon 9eb3819528 Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon 46a96049ba Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon edec8ea9d5 Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon 08e26ce3fd Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon ce456c3291 Apply suggestions from code review
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon 58fb1721a7 Update docs/book/src/quinn/certificate.md
Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
2021-01-18 09:30:32 +01:00
Timon Post b35df59298 round 2 2021-01-18 09:30:32 +01:00
Timon Post 70df232673 edit 2021-01-18 09:30:32 +01:00
Timon Post 386a2f24b0 Edit certbot section 2021-01-18 09:30:32 +01:00
Timon Post 0ea2a1bcab review round 1.0 2021-01-18 09:30:32 +01:00
Timon Post 82eb52ca5a merge introduction with this chapter 2021-01-18 09:30:32 +01:00
Timon Post 3fecf00890 Write certificate configuration chapter 2021-01-18 09:30:32 +01:00
Matthias Einwag 99649bf00f Congestion controller fixes
This change fixes 2 issues in the congestion controller:

Extra slow slow start
===

The congestion controller had an issue where it didn't ramp up by
doubling the window in the slow start phase as expected. The reason
here was the usage of the "congestion_blocked" field, which aims to
remove the avoid growing the window when there is no data to send.
The issue with the field was that the first incoming ACK for every batch
would increase the congestion window, which would let the next
call to `congestion_blocked()` return false, and thereby let the
congestion controller ignore all of the following ACKs in a received
batch up the point where the next `poll_transmit()` call is made and
the window is filled again. Since often all ACKs for one round-trip
arrive in a single batch that means only the first ACK had an effect
and the others where ignored -> which lead to increasing the
window by 1 MTU instead of doubling it in the slow start phase.

The new approach introduces a new `app_limited` field which
caches whether the last `poll_transmit` attempt couldn't produce
data because there was no application data available.

Numeric precision issue in congestion avoidance
===

The formula
```
self.window += self.config.max_datagram_size * bytes / self.window;
```
which is specified in the RFC requires floating point arithmetic.
If integer arithmetic is used, the multiplication of the first 2 values
yields about 1.7MB for 1300 byte packets. As soon as the window is
bigger than this value, the window won't change at all due the
division leading to 0.

The new implementation follow this guidance from the quic recovery
specification:

> In congestion avoidance, implementers that use an integer
> representation for congestion_window should be careful with division,
> and can use the alternative approach suggested in Section 2.1 of
> [RFC3465].
2021-01-14 20:23:12 -08:00
Matthias Einwag 1a544c37de Add recovery stats as part of ConnectionStats
This is an alternative version of #972, where we add the new stats
to ConnectionStats instead of exposing additional accessors.

The naming of `recovery` could probably be improved. `path` might
be an option. But where would we add something like packet loss?
That seems more like an overall stat.
2021-01-10 08:03:00 +01:00
Matthias Einwag 8722506c3b Rx frame stats
This adds frame stats for the receiving part, which had been
missing so far.
2021-01-09 08:01:09 +01:00
Dirkjan Ochtman 13f1169286 quinn-proto: generalize over read methods 2021-01-07 07:21:48 +01:00
Jean-Christophe BEGUE 69c620ac8f Read multiple chunks into a slice of Bytes 2021-01-06 21:51:17 +01:00
Jean-Christophe BEGUE 5754b3c67a Factorize proto read methods 2021-01-06 21:51:17 +01:00
Jean-Christophe BEGUE d19fee11fe Read ordered chunks from RecvStream 2021-01-06 21:51:17 +01:00
Timon Post a149c5d642 Logo update to static link. 2021-01-06 15:26:39 +01:00
Matthias Einwag 1ca7149de1 Allow to use the incoming IP address for sending outgoing packets
This is a follow-up for #943. When a socket is bound to a wildcard
IP address, sending the outgoing IP might use a different source IP
address than the one the packet was received on, since the OS might
not be able to identify the necessary route. This would lead packets
not allowing to reach the client.

This change adds a setting which will set an explicit source address
in all outgoing packets. The source address which will be used is
the local IP address which was used to receive the initial incoming
packet.
2021-01-06 09:57:13 +01:00
Benjamin Saunders 42fd00c20d Store MTU per-path 2021-01-06 06:58:43 +01:00
Benjamin Saunders af1effdedb Tweak naming/docs/signature 2021-01-06 06:58:43 +01:00
Benjamin Saunders 7436eb2d1b Replace inappropriate wrapping arithmetic 2021-01-06 06:58:43 +01:00
Benjamin Saunders a1223601ed Apply anti-amplification when peer migrates
Defends against amplification attacks where an existing connection is
hijacked by modifying the source address of a legitimate packet, as
required by the spec. Previously we only defended against similar
attacks involving brand new connections being created by an attacker.
2021-01-06 06:58:43 +01:00
Benjamin Saunders a01a4fa168 Check stream flow control correctness against issued credit
Previously, we checked against a quantity that might not have actually
been communicated to the peer yet, which would cause us to tolerate
illegally optimistic peers.
2021-01-05 13:52:11 +01:00
Benjamin Saunders a012a8829d More accurately track issued stream-level flow control credit 2021-01-05 13:52:11 +01:00
Benjamin Saunders bc3c07372a Improve robustness to large connection-level flow control 2021-01-05 13:52:11 +01:00
Benjamin Saunders a2e9dfc374 Validate flow control compliance of RESET_STREAM final offset 2021-01-05 13:52:11 +01:00
Benjamin Saunders 21b4988cd6 Factor out flow control validation from Recv::ingest 2021-01-05 13:52:11 +01:00
Benjamin Saunders 75634cce5d Represent reset final offset field with VarInt
Preserves constraints imposed by the wire encoding.
2021-01-05 13:52:11 +01:00
Benjamin Saunders c6cdbd2c46 Move final offset validation inside streams::Recv 2021-01-05 13:52:11 +01:00
Matthias Einwag 115fe2349c GSO platform support
This splits out the platform/socket parts for UDP GSO support
from #953 to reduce the amount of code to review.

This change mainly implements setting the segment size
socket option, and adds a runtime detection mechanism for
GSO support.
2021-01-05 13:42:23 +01:00
Jared Fowler 9b5d5b35a3 Fuzz packet decoding (#885) 2021-01-03 21:51:53 +01:00
Dirkjan Ochtman 9b19e23a68 Update link to native Gitter channel 2021-01-03 12:04:34 -08:00
Dirkjan Ochtman 79361e29b4 Tweak CidState::track_lifetime() style 2021-01-02 12:52:11 -08:00
Wenjie Li 6b3656630f Proactive CID rotation (#860) 2021-01-02 21:33:18 +01:00