diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:30:19 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:45:41 -0400 |
commit | 2b81143aa3505e2460b24b357996c2f21840ea58 (patch) | |
tree | 37f752fb85c563f965655cec834bb289fd831137 /net/dccp/ccids/lib | |
parent | 2f3e3bbad917c426d3aba03a535809e5699de156 (diff) |
dccp ccid-3: Always perform receiver RTT sampling
This updates the CCID-3 receiver in part with regard to errata 610 and 611
(http://www.rfc-editor.org/errata_list.php), which change RFC 4342 to use the
Receive Rate as specified in rfc3448bis, requiring to constantly sample the
RTT (or use a sender RTT).
Doing this requires reusing the RX history structure after dealing with a loss.
The patch does not resolve how to compute X_recv if the interval is less
than 1 RTT. A FIXME has been added (and is resolved in subsequent patch).
Furthermore, since this is all TFRC-based functionality, the RTT estimation
is now also performed by the dccp_tfrc_lib module. This further simplifies
the CCID-3 code.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net/dccp/ccids/lib')
-rw-r--r-- | net/dccp/ccids/lib/packet_history.c | 60 | ||||
-rw-r--r-- | net/dccp/ccids/lib/packet_history.h | 17 |
2 files changed, 59 insertions, 18 deletions
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index ee34b4564242..e2e250aa5c89 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c | |||
@@ -151,14 +151,31 @@ int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb) | |||
151 | } | 151 | } |
152 | EXPORT_SYMBOL_GPL(tfrc_rx_hist_duplicate); | 152 | EXPORT_SYMBOL_GPL(tfrc_rx_hist_duplicate); |
153 | 153 | ||
154 | |||
155 | static void __tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b) | ||
156 | { | ||
157 | struct tfrc_rx_hist_entry *tmp = h->ring[a]; | ||
158 | |||
159 | h->ring[a] = h->ring[b]; | ||
160 | h->ring[b] = tmp; | ||
161 | } | ||
162 | |||
154 | static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b) | 163 | static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b) |
155 | { | 164 | { |
156 | const u8 idx_a = tfrc_rx_hist_index(h, a), | 165 | __tfrc_rx_hist_swap(h, tfrc_rx_hist_index(h, a), |
157 | idx_b = tfrc_rx_hist_index(h, b); | 166 | tfrc_rx_hist_index(h, b)); |
158 | struct tfrc_rx_hist_entry *tmp = h->ring[idx_a]; | 167 | } |
159 | 168 | ||
160 | h->ring[idx_a] = h->ring[idx_b]; | 169 | /** |
161 | h->ring[idx_b] = tmp; | 170 | * tfrc_rx_hist_resume_rtt_sampling - Prepare RX history for RTT sampling |
171 | * This is called after loss detection has finished, when the history entry | ||
172 | * with the index of `loss_count' holds the highest-received sequence number. | ||
173 | * RTT sampling requires this information at ring[0] (tfrc_rx_hist_sample_rtt). | ||
174 | */ | ||
175 | static inline void tfrc_rx_hist_resume_rtt_sampling(struct tfrc_rx_hist *h) | ||
176 | { | ||
177 | __tfrc_rx_hist_swap(h, 0, tfrc_rx_hist_index(h, h->loss_count)); | ||
178 | h->loss_count = h->loss_start = 0; | ||
162 | } | 179 | } |
163 | 180 | ||
164 | /* | 181 | /* |
@@ -200,8 +217,7 @@ static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2 | |||
200 | 217 | ||
201 | if (dccp_loss_free(s2, s1, n1)) { | 218 | if (dccp_loss_free(s2, s1, n1)) { |
202 | /* hole is filled: S0, S2, and S1 are consecutive */ | 219 | /* hole is filled: S0, S2, and S1 are consecutive */ |
203 | h->loss_count = 0; | 220 | tfrc_rx_hist_resume_rtt_sampling(h); |
204 | h->loss_start = tfrc_rx_hist_index(h, 1); | ||
205 | } else | 221 | } else |
206 | /* gap between S2 and S1: just update loss_prev */ | 222 | /* gap between S2 and S1: just update loss_prev */ |
207 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2); | 223 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2); |
@@ -254,8 +270,7 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) | |||
254 | 270 | ||
255 | if (dccp_loss_free(s1, s2, n2)) { | 271 | if (dccp_loss_free(s1, s2, n2)) { |
256 | /* entire hole filled by S0, S3, S1, S2 */ | 272 | /* entire hole filled by S0, S3, S1, S2 */ |
257 | h->loss_start = tfrc_rx_hist_index(h, 2); | 273 | tfrc_rx_hist_resume_rtt_sampling(h); |
258 | h->loss_count = 0; | ||
259 | } else { | 274 | } else { |
260 | /* gap remains between S1 and S2 */ | 275 | /* gap remains between S1 and S2 */ |
261 | h->loss_start = tfrc_rx_hist_index(h, 1); | 276 | h->loss_start = tfrc_rx_hist_index(h, 1); |
@@ -299,8 +314,7 @@ static void __three_after_loss(struct tfrc_rx_hist *h) | |||
299 | 314 | ||
300 | if (dccp_loss_free(s2, s3, n3)) { | 315 | if (dccp_loss_free(s2, s3, n3)) { |
301 | /* no gap between S2 and S3: entire hole is filled */ | 316 | /* no gap between S2 and S3: entire hole is filled */ |
302 | h->loss_start = tfrc_rx_hist_index(h, 3); | 317 | tfrc_rx_hist_resume_rtt_sampling(h); |
303 | h->loss_count = 0; | ||
304 | } else { | 318 | } else { |
305 | /* gap between S2 and S3 */ | 319 | /* gap between S2 and S3 */ |
306 | h->loss_start = tfrc_rx_hist_index(h, 2); | 320 | h->loss_start = tfrc_rx_hist_index(h, 2); |
@@ -340,6 +354,7 @@ int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, | |||
340 | 354 | ||
341 | if (h->loss_count == 0) { | 355 | if (h->loss_count == 0) { |
342 | __do_track_loss(h, skb, ndp); | 356 | __do_track_loss(h, skb, ndp); |
357 | tfrc_rx_hist_sample_rtt(h, skb); | ||
343 | } else if (h->loss_count == 1) { | 358 | } else if (h->loss_count == 1) { |
344 | __one_after_loss(h, skb, ndp); | 359 | __one_after_loss(h, skb, ndp); |
345 | } else if (h->loss_count != 2) { | 360 | } else if (h->loss_count != 2) { |
@@ -435,11 +450,24 @@ static inline struct tfrc_rx_hist_entry * | |||
435 | * Based on ideas presented in RFC 4342, 8.1. Returns 0 if it was not able | 450 | * Based on ideas presented in RFC 4342, 8.1. Returns 0 if it was not able |
436 | * to compute a sample with given data - calling function should check this. | 451 | * to compute a sample with given data - calling function should check this. |
437 | */ | 452 | */ |
438 | u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb) | 453 | void tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb) |
439 | { | 454 | { |
440 | u32 sample = 0, | 455 | u32 sample = 0, delta_v; |
441 | delta_v = SUB16(dccp_hdr(skb)->dccph_ccval, | 456 | |
442 | tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval); | 457 | /* |
458 | * When not to sample: | ||
459 | * - on non-data packets | ||
460 | * (RFC 4342, 8.1: CCVal only fully defined for data packets); | ||
461 | * - when no data packets have been received yet | ||
462 | * (FIXME: using sampled packet size as indicator here); | ||
463 | * - as long as there are gaps in the sequence space (pending loss). | ||
464 | */ | ||
465 | if (!dccp_data_packet(skb) || h->packet_size == 0 || | ||
466 | tfrc_rx_hist_loss_pending(h)) | ||
467 | return; | ||
468 | |||
469 | delta_v = SUB16(dccp_hdr(skb)->dccph_ccval, | ||
470 | tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval); | ||
443 | 471 | ||
444 | if (delta_v < 1 || delta_v > 4) { /* unsuitable CCVal delta */ | 472 | if (delta_v < 1 || delta_v > 4) { /* unsuitable CCVal delta */ |
445 | if (h->rtt_sample_prev == 2) { /* previous candidate stored */ | 473 | if (h->rtt_sample_prev == 2) { /* previous candidate stored */ |
@@ -479,6 +507,6 @@ u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb) | |||
479 | h->rtt_sample_prev = 0; /* use current entry as next reference */ | 507 | h->rtt_sample_prev = 0; /* use current entry as next reference */ |
480 | keep_ref_for_next_time: | 508 | keep_ref_for_next_time: |
481 | 509 | ||
482 | return sample; | 510 | h->rtt_estimate = tfrc_ewma(h->rtt_estimate, sample, 9); |
483 | } | 511 | } |
484 | EXPORT_SYMBOL_GPL(tfrc_rx_hist_sample_rtt); | 512 | EXPORT_SYMBOL_GPL(tfrc_rx_hist_sample_rtt); |
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index b7c87a1a2720..ba5832bbc348 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h | |||
@@ -91,6 +91,7 @@ struct tfrc_rx_hist_entry { | |||
91 | * @loss_count: Number of entries in circular history | 91 | * @loss_count: Number of entries in circular history |
92 | * @loss_start: Movable index (for loss detection) | 92 | * @loss_start: Movable index (for loss detection) |
93 | * @rtt_sample_prev: Used during RTT sampling, points to candidate entry | 93 | * @rtt_sample_prev: Used during RTT sampling, points to candidate entry |
94 | * @rtt_estimate: Receiver RTT estimate | ||
94 | * @packet_size: Packet size in bytes (as per RFC 3448, 3.1) | 95 | * @packet_size: Packet size in bytes (as per RFC 3448, 3.1) |
95 | * @bytes_recvd: Number of bytes received since last sending feedback | 96 | * @bytes_recvd: Number of bytes received since last sending feedback |
96 | */ | 97 | */ |
@@ -98,7 +99,10 @@ struct tfrc_rx_hist { | |||
98 | struct tfrc_rx_hist_entry *ring[TFRC_NDUPACK + 1]; | 99 | struct tfrc_rx_hist_entry *ring[TFRC_NDUPACK + 1]; |
99 | u8 loss_count:2, | 100 | u8 loss_count:2, |
100 | loss_start:2; | 101 | loss_start:2; |
102 | /* Receiver RTT sampling */ | ||
101 | #define rtt_sample_prev loss_start | 103 | #define rtt_sample_prev loss_start |
104 | u32 rtt_estimate; | ||
105 | /* Receiver sampling of application payload lengths */ | ||
102 | u32 packet_size, | 106 | u32 packet_size, |
103 | bytes_recvd; | 107 | bytes_recvd; |
104 | }; | 108 | }; |
@@ -154,6 +158,15 @@ static inline u32 tfrc_rx_hist_packet_size(const struct tfrc_rx_hist *h) | |||
154 | return TCP_MIN_RCVMSS; | 158 | return TCP_MIN_RCVMSS; |
155 | } | 159 | } |
156 | return h->packet_size; | 160 | return h->packet_size; |
161 | |||
162 | } | ||
163 | static inline u32 tfrc_rx_hist_rtt(const struct tfrc_rx_hist *h) | ||
164 | { | ||
165 | if (h->rtt_estimate == 0) { | ||
166 | DCCP_WARN("No RTT estimate available, using fallback RTT\n"); | ||
167 | return DCCP_FALLBACK_RTT; | ||
168 | } | ||
169 | return h->rtt_estimate; | ||
157 | } | 170 | } |
158 | 171 | ||
159 | extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h, | 172 | extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h, |
@@ -167,8 +180,8 @@ extern int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, | |||
167 | struct sk_buff *skb, const u64 ndp, | 180 | struct sk_buff *skb, const u64 ndp, |
168 | u32 (*first_li)(struct sock *sk), | 181 | u32 (*first_li)(struct sock *sk), |
169 | struct sock *sk); | 182 | struct sock *sk); |
170 | extern u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, | 183 | extern void tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, |
171 | const struct sk_buff *skb); | 184 | const struct sk_buff *skb); |
172 | extern int tfrc_rx_hist_init(struct tfrc_rx_hist *h, struct sock *sk); | 185 | extern int tfrc_rx_hist_init(struct tfrc_rx_hist *h, struct sock *sk); |
173 | extern void tfrc_rx_hist_purge(struct tfrc_rx_hist *h); | 186 | extern void tfrc_rx_hist_purge(struct tfrc_rx_hist *h); |
174 | 187 | ||