diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2006-11-28 16:51:42 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:31:01 -0500 |
commit | a79ef76f4d8424324c2f108824a7398571193f43 (patch) | |
tree | a80e84d19c867e1432fc05ae50199487ce2ea2b2 /net/dccp/ccids | |
parent | 841bac1d607d8bf2e068e4b24393fb77372814e3 (diff) |
[DCCP] ccid3: Larger initial windows
This implements the larger-initial-windows feature for CCID 3, as described in
section 5 of RFC 4342. When the first feedback packet arrives, the sender can
send up to 2..4 packets per RTT, instead of just one.
The patch further
* reduces the number of timestamping calls by passing the timestamp value
(which is computed in one of the calling functions anyway) as argument
* renames one constant with a very long name into one which is shorter and
resembles the one in RFC 3448 (t_mbi)
* simplifies some of the min_t/max_t cases where both `x', `y' have the same
type
Commiter note: renamed TFRC_t_mbi to TFRC_T_MBI, to follow Linux coding style.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/dccp/ccids')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 66 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.h | 4 |
2 files changed, 37 insertions, 33 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 05513f3df652..aa5440ee20ae 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -128,7 +128,8 @@ static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx) | |||
128 | * X = max(min(2 * X, 2 * X_recv), s / R); | 128 | * X = max(min(2 * X, 2 * X_recv), s / R); |
129 | * tld = now; | 129 | * tld = now; |
130 | */ | 130 | */ |
131 | static void ccid3_hc_tx_update_x(struct sock *sk) | 131 | static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now) |
132 | |||
132 | { | 133 | { |
133 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | 134 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); |
134 | const __u32 old_x = hctx->ccid3hctx_x; | 135 | const __u32 old_x = hctx->ccid3hctx_x; |
@@ -138,23 +139,20 @@ static void ccid3_hc_tx_update_x(struct sock *sk) | |||
138 | hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s, | 139 | hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s, |
139 | hctx->ccid3hctx_rtt, | 140 | hctx->ccid3hctx_rtt, |
140 | hctx->ccid3hctx_p); | 141 | hctx->ccid3hctx_p); |
141 | hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_calc, | 142 | hctx->ccid3hctx_x = max_t(u32, min(hctx->ccid3hctx_x_calc, |
142 | 2 * hctx->ccid3hctx_x_recv), | 143 | hctx->ccid3hctx_x_recv * 2), |
143 | (hctx->ccid3hctx_s / | 144 | hctx->ccid3hctx_s / TFRC_T_MBI); |
144 | TFRC_MAX_BACK_OFF_TIME)); | 145 | |
145 | } else { | 146 | } else if (timeval_delta(now, &hctx->ccid3hctx_t_ld) >= |
146 | struct timeval now; | 147 | hctx->ccid3hctx_rtt) { |
148 | hctx->ccid3hctx_x = max(min(hctx->ccid3hctx_x_recv, | ||
149 | hctx->ccid3hctx_x ) * 2, | ||
150 | usecs_div(hctx->ccid3hctx_s, | ||
151 | hctx->ccid3hctx_rtt) ); | ||
152 | hctx->ccid3hctx_t_ld = *now; | ||
153 | } else | ||
154 | ccid3_pr_debug("Not changing X\n"); | ||
147 | 155 | ||
148 | dccp_timestamp(sk, &now); | ||
149 | if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >= | ||
150 | hctx->ccid3hctx_rtt) { | ||
151 | hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv, | ||
152 | hctx->ccid3hctx_x) * 2, | ||
153 | usecs_div(hctx->ccid3hctx_s, | ||
154 | hctx->ccid3hctx_rtt)); | ||
155 | hctx->ccid3hctx_t_ld = now; | ||
156 | } | ||
157 | } | ||
158 | if (hctx->ccid3hctx_x != old_x) | 156 | if (hctx->ccid3hctx_x != old_x) |
159 | ccid3_update_send_time(hctx); | 157 | ccid3_update_send_time(hctx); |
160 | } | 158 | } |
@@ -196,12 +194,9 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) | |||
196 | 194 | ||
197 | switch (hctx->ccid3hctx_state) { | 195 | switch (hctx->ccid3hctx_state) { |
198 | case TFRC_SSTATE_NO_FBACK: | 196 | case TFRC_SSTATE_NO_FBACK: |
199 | /* Halve send rate */ | 197 | /* RFC 3448, 4.4: Halve send rate directly */ |
200 | hctx->ccid3hctx_x /= 2; | 198 | hctx->ccid3hctx_x = min_t(u32, hctx->ccid3hctx_x / 2, |
201 | if (hctx->ccid3hctx_x < (hctx->ccid3hctx_s / | 199 | hctx->ccid3hctx_s / TFRC_T_MBI); |
202 | TFRC_MAX_BACK_OFF_TIME)) | ||
203 | hctx->ccid3hctx_x = (hctx->ccid3hctx_s / | ||
204 | TFRC_MAX_BACK_OFF_TIME); | ||
205 | 200 | ||
206 | ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d " | 201 | ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d " |
207 | "bytes/s\n", | 202 | "bytes/s\n", |
@@ -221,6 +216,8 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) | |||
221 | if (!hctx->ccid3hctx_idle || | 216 | if (!hctx->ccid3hctx_idle || |
222 | (hctx->ccid3hctx_x_recv >= | 217 | (hctx->ccid3hctx_x_recv >= |
223 | 4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) { | 218 | 4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) { |
219 | struct timeval now; | ||
220 | |||
224 | ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n", | 221 | ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n", |
225 | dccp_role(sk), sk, | 222 | dccp_role(sk), sk, |
226 | ccid3_tx_state_name(hctx->ccid3hctx_state)); | 223 | ccid3_tx_state_name(hctx->ccid3hctx_state)); |
@@ -238,12 +235,13 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data) | |||
238 | if (hctx->ccid3hctx_p < TFRC_SMALLEST_P || | 235 | if (hctx->ccid3hctx_p < TFRC_SMALLEST_P || |
239 | hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) | 236 | hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) |
240 | hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, | 237 | hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, |
241 | hctx->ccid3hctx_s / (2 * TFRC_MAX_BACK_OFF_TIME)); | 238 | hctx->ccid3hctx_s / (2 * TFRC_T_MBI)); |
242 | else | 239 | else |
243 | hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4; | 240 | hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4; |
244 | 241 | ||
245 | /* Update sending rate */ | 242 | /* Update sending rate */ |
246 | ccid3_hc_tx_update_x(sk); | 243 | dccp_timestamp(sk, &now); |
244 | ccid3_hc_tx_update_x(sk, &now); | ||
247 | } | 245 | } |
248 | /* | 246 | /* |
249 | * Schedule no feedback timer to expire in | 247 | * Schedule no feedback timer to expire in |
@@ -473,11 +471,21 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
473 | * q is a constant, RFC 3448 recomments 0.9 | 471 | * q is a constant, RFC 3448 recomments 0.9 |
474 | */ | 472 | */ |
475 | if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) { | 473 | if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) { |
474 | /* Use Larger Initial Windows [RFC 4342, sec. 5] | ||
475 | * We deviate in that we use `s' instead of `MSS'. */ | ||
476 | u16 w_init = max( 4 * hctx->ccid3hctx_s, | ||
477 | max(2 * hctx->ccid3hctx_s, 4380)); | ||
478 | hctx->ccid3hctx_rtt = r_sample; | ||
479 | hctx->ccid3hctx_x = usecs_div(w_init, r_sample); | ||
480 | hctx->ccid3hctx_t_ld = now; | ||
481 | |||
482 | ccid3_update_send_time(hctx); | ||
476 | ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); | 483 | ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK); |
477 | hctx->ccid3hctx_rtt = r_sample; | 484 | } else { |
478 | } else | ||
479 | hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 + | 485 | hctx->ccid3hctx_rtt = (hctx->ccid3hctx_rtt * 9) / 10 + |
480 | r_sample / 10; | 486 | r_sample / 10; |
487 | ccid3_hc_tx_update_x(sk, &now); | ||
488 | } | ||
481 | 489 | ||
482 | ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, " | 490 | ccid3_pr_debug("%s, sk=%p, New RTT estimate=%uus, " |
483 | "r_sample=%us\n", dccp_role(sk), sk, | 491 | "r_sample=%us\n", dccp_role(sk), sk, |
@@ -502,9 +510,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
502 | /* unschedule no feedback timer */ | 510 | /* unschedule no feedback timer */ |
503 | sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); | 511 | sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); |
504 | 512 | ||
505 | /* Update sending rate (and likely t_ipi, t_nom, and delta) */ | ||
506 | ccid3_hc_tx_update_x(sk); | ||
507 | |||
508 | /* remove all packets older than the one acked from history */ | 513 | /* remove all packets older than the one acked from history */ |
509 | dccp_tx_hist_purge_older(ccid3_tx_hist, | 514 | dccp_tx_hist_purge_older(ccid3_tx_hist, |
510 | &hctx->ccid3hctx_hist, packet); | 515 | &hctx->ccid3hctx_hist, packet); |
@@ -514,7 +519,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
514 | */ | 519 | */ |
515 | sk->sk_write_space(sk); | 520 | sk->sk_write_space(sk); |
516 | 521 | ||
517 | |||
518 | /* Update timeout interval. We use the alternative variant of | 522 | /* Update timeout interval. We use the alternative variant of |
519 | * [RFC 3448, 3.1] which sets the upper bound of t_rto to one | 523 | * [RFC 3448, 3.1] which sets the upper bound of t_rto to one |
520 | * second, as it is suggested for TCP (see RFC 2988, 2.4). */ | 524 | * second, as it is suggested for TCP (see RFC 2988, 2.4). */ |
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index dbb884426dfa..27cb20ae1da8 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h | |||
@@ -48,8 +48,8 @@ | |||
48 | /* In usecs - half the scheduling granularity as per RFC3448 4.6 */ | 48 | /* In usecs - half the scheduling granularity as per RFC3448 4.6 */ |
49 | #define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ)) | 49 | #define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ)) |
50 | 50 | ||
51 | /* In seconds */ | 51 | /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */ |
52 | #define TFRC_MAX_BACK_OFF_TIME 64 | 52 | #define TFRC_T_MBI 64 |
53 | 53 | ||
54 | #define TFRC_SMALLEST_P 40 | 54 | #define TFRC_SMALLEST_P 40 |
55 | 55 | ||