diff options
author | David S. Miller <davem@davemloft.net> | 2010-09-15 23:21:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-15 23:21:48 -0400 |
commit | 7fedd7e5dfeb0f6bd69ee120b5c44a5e49892e47 (patch) | |
tree | 01be8759e2177d53c3766fa9e1593cd8b83b1026 /net | |
parent | 1a19eb753a591f8b39946b7fda91b25f07454835 (diff) | |
parent | 37efb03fbd0935f5f85a0538c46b53be5cf40504 (diff) |
Merge branch 'dccp' of git://eden-feed.erg.abdn.ac.uk/net-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 110 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.h | 21 | ||||
-rw-r--r-- | net/dccp/ccids/lib/packet_history.c | 39 | ||||
-rw-r--r-- | net/dccp/ccids/lib/packet_history.h | 22 |
4 files changed, 73 insertions, 119 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 278e17069322..ce8059130070 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -91,19 +91,16 @@ static inline u64 rfc3390_initial_rate(struct sock *sk) | |||
91 | return scaled_div(w_init << 6, hc->tx_rtt); | 91 | return scaled_div(w_init << 6, hc->tx_rtt); |
92 | } | 92 | } |
93 | 93 | ||
94 | /* | 94 | /** |
95 | * Recalculate t_ipi and delta (should be called whenever X changes) | 95 | * ccid3_update_send_interval - Calculate new t_ipi = s / X_inst |
96 | * This respects the granularity of X_inst (64 * bytes/second). | ||
96 | */ | 97 | */ |
97 | static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hc) | 98 | static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hc) |
98 | { | 99 | { |
99 | /* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */ | ||
100 | hc->tx_t_ipi = scaled_div32(((u64)hc->tx_s) << 6, hc->tx_x); | 100 | hc->tx_t_ipi = scaled_div32(((u64)hc->tx_s) << 6, hc->tx_x); |
101 | 101 | ||
102 | /* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */ | 102 | ccid3_pr_debug("t_ipi=%u, s=%u, X=%u\n", hc->tx_t_ipi, |
103 | hc->tx_delta = min_t(u32, hc->tx_t_ipi / 2, TFRC_OPSYS_HALF_TIME_GRAN); | 103 | hc->tx_s, (unsigned)(hc->tx_x >> 6)); |
104 | |||
105 | ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n", hc->tx_t_ipi, | ||
106 | hc->tx_delta, hc->tx_s, (unsigned)(hc->tx_x >> 6)); | ||
107 | } | 104 | } |
108 | 105 | ||
109 | static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hc, ktime_t now) | 106 | static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hc, ktime_t now) |
@@ -332,15 +329,15 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
332 | delay = ktime_us_delta(hc->tx_t_nom, now); | 329 | delay = ktime_us_delta(hc->tx_t_nom, now); |
333 | ccid3_pr_debug("delay=%ld\n", (long)delay); | 330 | ccid3_pr_debug("delay=%ld\n", (long)delay); |
334 | /* | 331 | /* |
335 | * Scheduling of packet transmissions [RFC 3448, 4.6] | 332 | * Scheduling of packet transmissions (RFC 5348, 8.3) |
336 | * | 333 | * |
337 | * if (t_now > t_nom - delta) | 334 | * if (t_now > t_nom - delta) |
338 | * // send the packet now | 335 | * // send the packet now |
339 | * else | 336 | * else |
340 | * // send the packet in (t_nom - t_now) milliseconds. | 337 | * // send the packet in (t_nom - t_now) milliseconds. |
341 | */ | 338 | */ |
342 | if (delay - (s64)hc->tx_delta >= 1000) | 339 | if (delay >= TFRC_T_DELTA) |
343 | return (u32)delay / 1000L; | 340 | return (u32)delay / USEC_PER_MSEC; |
344 | 341 | ||
345 | ccid3_hc_tx_update_win_count(hc, now); | 342 | ccid3_hc_tx_update_win_count(hc, now); |
346 | break; | 343 | break; |
@@ -373,6 +370,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
373 | { | 370 | { |
374 | struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); | 371 | struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); |
375 | struct ccid3_options_received *opt_recv = &hc->tx_options_received; | 372 | struct ccid3_options_received *opt_recv = &hc->tx_options_received; |
373 | struct tfrc_tx_hist_entry *acked; | ||
376 | ktime_t now; | 374 | ktime_t now; |
377 | unsigned long t_nfb; | 375 | unsigned long t_nfb; |
378 | u32 pinv, r_sample; | 376 | u32 pinv, r_sample; |
@@ -386,17 +384,24 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
386 | hc->tx_state != TFRC_SSTATE_NO_FBACK) | 384 | hc->tx_state != TFRC_SSTATE_NO_FBACK) |
387 | return; | 385 | return; |
388 | 386 | ||
389 | now = ktime_get_real(); | 387 | /* |
390 | 388 | * Locate the acknowledged packet in the TX history. | |
391 | /* Estimate RTT from history if ACK number is valid */ | 389 | * |
392 | r_sample = tfrc_tx_hist_rtt(hc->tx_hist, | 390 | * Returning "entry not found" here can for instance happen when |
393 | DCCP_SKB_CB(skb)->dccpd_ack_seq, now); | 391 | * - the host has not sent out anything (e.g. a passive server), |
394 | if (r_sample == 0) { | 392 | * - the Ack is outdated (packet with higher Ack number was received), |
395 | DCCP_WARN("%s(%p): %s with bogus ACK-%llu\n", dccp_role(sk), sk, | 393 | * - it is a bogus Ack (for a packet not sent on this connection). |
396 | dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type), | 394 | */ |
397 | (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq); | 395 | acked = tfrc_tx_hist_find_entry(hc->tx_hist, dccp_hdr_ack_seq(skb)); |
396 | if (acked == NULL) | ||
398 | return; | 397 | return; |
399 | } | 398 | /* For the sake of RTT sampling, ignore/remove all older entries */ |
399 | tfrc_tx_hist_purge(&acked->next); | ||
400 | |||
401 | /* Update the moving average for the RTT estimate (RFC 3448, 4.3) */ | ||
402 | now = ktime_get_real(); | ||
403 | r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, acked->stamp)); | ||
404 | hc->tx_rtt = tfrc_ewma(hc->tx_rtt, r_sample, 9); | ||
400 | 405 | ||
401 | /* Update receive rate in units of 64 * bytes/second */ | 406 | /* Update receive rate in units of 64 * bytes/second */ |
402 | hc->tx_x_recv = opt_recv->ccid3or_receive_rate; | 407 | hc->tx_x_recv = opt_recv->ccid3or_receive_rate; |
@@ -408,11 +413,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
408 | hc->tx_p = 0; | 413 | hc->tx_p = 0; |
409 | else /* can not exceed 100% */ | 414 | else /* can not exceed 100% */ |
410 | hc->tx_p = scaled_div(1, pinv); | 415 | hc->tx_p = scaled_div(1, pinv); |
411 | /* | 416 | |
412 | * Validate new RTT sample and update moving average | ||
413 | */ | ||
414 | r_sample = dccp_sample_rtt(sk, r_sample); | ||
415 | hc->tx_rtt = tfrc_ewma(hc->tx_rtt, r_sample, 9); | ||
416 | /* | 417 | /* |
417 | * Update allowed sending rate X as per draft rfc3448bis-00, 4.2/3 | 418 | * Update allowed sending rate X as per draft rfc3448bis-00, 4.2/3 |
418 | */ | 419 | */ |
@@ -484,60 +485,31 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, | |||
484 | unsigned char len, u16 idx, | 485 | unsigned char len, u16 idx, |
485 | unsigned char *value) | 486 | unsigned char *value) |
486 | { | 487 | { |
487 | int rc = 0; | ||
488 | const struct dccp_sock *dp = dccp_sk(sk); | ||
489 | struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); | 488 | struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); |
490 | struct ccid3_options_received *opt_recv = &hc->tx_options_received; | 489 | struct ccid3_options_received *opt_recv = &hc->tx_options_received; |
491 | __be32 opt_val; | 490 | __be32 opt_val; |
492 | 491 | ||
493 | if (opt_recv->ccid3or_seqno != dp->dccps_gsr) { | ||
494 | opt_recv->ccid3or_seqno = dp->dccps_gsr; | ||
495 | opt_recv->ccid3or_loss_event_rate = ~0; | ||
496 | opt_recv->ccid3or_loss_intervals_idx = 0; | ||
497 | opt_recv->ccid3or_loss_intervals_len = 0; | ||
498 | opt_recv->ccid3or_receive_rate = 0; | ||
499 | } | ||
500 | |||
501 | switch (option) { | 492 | switch (option) { |
493 | case TFRC_OPT_RECEIVE_RATE: | ||
502 | case TFRC_OPT_LOSS_EVENT_RATE: | 494 | case TFRC_OPT_LOSS_EVENT_RATE: |
503 | if (unlikely(len != 4)) { | 495 | if (unlikely(len != 4)) { |
504 | DCCP_WARN("%s(%p), invalid len %d " | 496 | DCCP_WARN("%s(%p), invalid len %d for %u\n", |
505 | "for TFRC_OPT_LOSS_EVENT_RATE\n", | 497 | dccp_role(sk), sk, len, option); |
506 | dccp_role(sk), sk, len); | 498 | return -EINVAL; |
507 | rc = -EINVAL; | ||
508 | } else { | ||
509 | opt_val = get_unaligned((__be32 *)value); | ||
510 | opt_recv->ccid3or_loss_event_rate = ntohl(opt_val); | ||
511 | ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n", | ||
512 | dccp_role(sk), sk, | ||
513 | opt_recv->ccid3or_loss_event_rate); | ||
514 | } | 499 | } |
515 | break; | 500 | opt_val = ntohl(get_unaligned((__be32 *)value)); |
516 | case TFRC_OPT_LOSS_INTERVALS: | 501 | |
517 | opt_recv->ccid3or_loss_intervals_idx = idx; | 502 | if (option == TFRC_OPT_RECEIVE_RATE) { |
518 | opt_recv->ccid3or_loss_intervals_len = len; | 503 | opt_recv->ccid3or_receive_rate = opt_val; |
519 | ccid3_pr_debug("%s(%p), LOSS_INTERVALS=(%u, %u)\n", | ||
520 | dccp_role(sk), sk, | ||
521 | opt_recv->ccid3or_loss_intervals_idx, | ||
522 | opt_recv->ccid3or_loss_intervals_len); | ||
523 | break; | ||
524 | case TFRC_OPT_RECEIVE_RATE: | ||
525 | if (unlikely(len != 4)) { | ||
526 | DCCP_WARN("%s(%p), invalid len %d " | ||
527 | "for TFRC_OPT_RECEIVE_RATE\n", | ||
528 | dccp_role(sk), sk, len); | ||
529 | rc = -EINVAL; | ||
530 | } else { | ||
531 | opt_val = get_unaligned((__be32 *)value); | ||
532 | opt_recv->ccid3or_receive_rate = ntohl(opt_val); | ||
533 | ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n", | 504 | ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n", |
534 | dccp_role(sk), sk, | 505 | dccp_role(sk), sk, opt_val); |
535 | opt_recv->ccid3or_receive_rate); | 506 | } else { |
507 | opt_recv->ccid3or_loss_event_rate = opt_val; | ||
508 | ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n", | ||
509 | dccp_role(sk), sk, opt_val); | ||
536 | } | 510 | } |
537 | break; | ||
538 | } | 511 | } |
539 | 512 | return 0; | |
540 | return rc; | ||
541 | } | 513 | } |
542 | 514 | ||
543 | static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) | 515 | static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) |
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index b7e569c22f36..9eb90b863abd 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h | |||
@@ -45,12 +45,22 @@ | |||
45 | /* Two seconds as per RFC 5348, 4.2 */ | 45 | /* Two seconds as per RFC 5348, 4.2 */ |
46 | #define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC) | 46 | #define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC) |
47 | 47 | ||
48 | /* In usecs - half the scheduling granularity as per RFC3448 4.6 */ | ||
49 | #define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ)) | ||
50 | |||
51 | /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */ | 48 | /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */ |
52 | #define TFRC_T_MBI 64 | 49 | #define TFRC_T_MBI 64 |
53 | 50 | ||
51 | /* | ||
52 | * The t_delta parameter (RFC 5348, 8.3): delays of less than %USEC_PER_MSEC are | ||
53 | * rounded down to 0, since sk_reset_timer() here uses millisecond granularity. | ||
54 | * Hence we can use a constant t_delta = %USEC_PER_MSEC when HZ >= 500. A coarse | ||
55 | * resolution of HZ < 500 means that the error is below one timer tick (t_gran) | ||
56 | * when using the constant t_delta = t_gran / 2 = %USEC_PER_SEC / (2 * HZ). | ||
57 | */ | ||
58 | #if (HZ >= 500) | ||
59 | # define TFRC_T_DELTA USEC_PER_MSEC | ||
60 | #else | ||
61 | # define TFRC_T_DELTA (USEC_PER_SEC / (2 * HZ)) | ||
62 | #endif | ||
63 | |||
54 | enum ccid3_options { | 64 | enum ccid3_options { |
55 | TFRC_OPT_LOSS_EVENT_RATE = 192, | 65 | TFRC_OPT_LOSS_EVENT_RATE = 192, |
56 | TFRC_OPT_LOSS_INTERVALS = 193, | 66 | TFRC_OPT_LOSS_INTERVALS = 193, |
@@ -58,9 +68,6 @@ enum ccid3_options { | |||
58 | }; | 68 | }; |
59 | 69 | ||
60 | struct ccid3_options_received { | 70 | struct ccid3_options_received { |
61 | u64 ccid3or_seqno:48, | ||
62 | ccid3or_loss_intervals_idx:16; | ||
63 | u16 ccid3or_loss_intervals_len; | ||
64 | u32 ccid3or_loss_event_rate; | 71 | u32 ccid3or_loss_event_rate; |
65 | u32 ccid3or_receive_rate; | 72 | u32 ccid3or_receive_rate; |
66 | }; | 73 | }; |
@@ -90,7 +97,6 @@ enum ccid3_hc_tx_states { | |||
90 | * @tx_no_feedback_timer: Handle to no feedback timer | 97 | * @tx_no_feedback_timer: Handle to no feedback timer |
91 | * @tx_t_ld: Time last doubled during slow start | 98 | * @tx_t_ld: Time last doubled during slow start |
92 | * @tx_t_nom: Nominal send time of next packet | 99 | * @tx_t_nom: Nominal send time of next packet |
93 | * @tx_delta: Send timer delta (RFC 3448, 4.6) in usecs | ||
94 | * @tx_hist: Packet history | 100 | * @tx_hist: Packet history |
95 | * @tx_options_received: Parsed set of retrieved options | 101 | * @tx_options_received: Parsed set of retrieved options |
96 | */ | 102 | */ |
@@ -109,7 +115,6 @@ struct ccid3_hc_tx_sock { | |||
109 | struct timer_list tx_no_feedback_timer; | 115 | struct timer_list tx_no_feedback_timer; |
110 | ktime_t tx_t_ld; | 116 | ktime_t tx_t_ld; |
111 | ktime_t tx_t_nom; | 117 | ktime_t tx_t_nom; |
112 | u32 tx_delta; | ||
113 | struct tfrc_tx_hist_entry *tx_hist; | 118 | struct tfrc_tx_hist_entry *tx_hist; |
114 | struct ccid3_options_received tx_options_received; | 119 | struct ccid3_options_received tx_options_received; |
115 | }; | 120 | }; |
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index 3a4f414e94a0..de8fe294bf0b 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c | |||
@@ -38,18 +38,6 @@ | |||
38 | #include "packet_history.h" | 38 | #include "packet_history.h" |
39 | #include "../../dccp.h" | 39 | #include "../../dccp.h" |
40 | 40 | ||
41 | /** | ||
42 | * tfrc_tx_hist_entry - Simple singly-linked TX history list | ||
43 | * @next: next oldest entry (LIFO order) | ||
44 | * @seqno: sequence number of this entry | ||
45 | * @stamp: send time of packet with sequence number @seqno | ||
46 | */ | ||
47 | struct tfrc_tx_hist_entry { | ||
48 | struct tfrc_tx_hist_entry *next; | ||
49 | u64 seqno; | ||
50 | ktime_t stamp; | ||
51 | }; | ||
52 | |||
53 | /* | 41 | /* |
54 | * Transmitter History Routines | 42 | * Transmitter History Routines |
55 | */ | 43 | */ |
@@ -71,15 +59,6 @@ void tfrc_tx_packet_history_exit(void) | |||
71 | } | 59 | } |
72 | } | 60 | } |
73 | 61 | ||
74 | static struct tfrc_tx_hist_entry * | ||
75 | tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno) | ||
76 | { | ||
77 | while (head != NULL && head->seqno != seqno) | ||
78 | head = head->next; | ||
79 | |||
80 | return head; | ||
81 | } | ||
82 | |||
83 | int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno) | 62 | int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno) |
84 | { | 63 | { |
85 | struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist_slab, gfp_any()); | 64 | struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist_slab, gfp_any()); |
@@ -107,24 +86,6 @@ void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp) | |||
107 | *headp = NULL; | 86 | *headp = NULL; |
108 | } | 87 | } |
109 | 88 | ||
110 | u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, const u64 seqno, | ||
111 | const ktime_t now) | ||
112 | { | ||
113 | u32 rtt = 0; | ||
114 | struct tfrc_tx_hist_entry *packet = tfrc_tx_hist_find_entry(head, seqno); | ||
115 | |||
116 | if (packet != NULL) { | ||
117 | rtt = ktime_us_delta(now, packet->stamp); | ||
118 | /* | ||
119 | * Garbage-collect older (irrelevant) entries: | ||
120 | */ | ||
121 | tfrc_tx_hist_purge(&packet->next); | ||
122 | } | ||
123 | |||
124 | return rtt; | ||
125 | } | ||
126 | |||
127 | |||
128 | /* | 89 | /* |
129 | * Receiver History Routines | 90 | * Receiver History Routines |
130 | */ | 91 | */ |
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index 7df6c5299999..7ee4a9d9d335 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h | |||
@@ -40,12 +40,28 @@ | |||
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include "tfrc.h" | 41 | #include "tfrc.h" |
42 | 42 | ||
43 | struct tfrc_tx_hist_entry; | 43 | /** |
44 | * tfrc_tx_hist_entry - Simple singly-linked TX history list | ||
45 | * @next: next oldest entry (LIFO order) | ||
46 | * @seqno: sequence number of this entry | ||
47 | * @stamp: send time of packet with sequence number @seqno | ||
48 | */ | ||
49 | struct tfrc_tx_hist_entry { | ||
50 | struct tfrc_tx_hist_entry *next; | ||
51 | u64 seqno; | ||
52 | ktime_t stamp; | ||
53 | }; | ||
54 | |||
55 | static inline struct tfrc_tx_hist_entry * | ||
56 | tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno) | ||
57 | { | ||
58 | while (head != NULL && head->seqno != seqno) | ||
59 | head = head->next; | ||
60 | return head; | ||
61 | } | ||
44 | 62 | ||
45 | extern int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno); | 63 | extern int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno); |
46 | extern void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp); | 64 | extern void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp); |
47 | extern u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, | ||
48 | const u64 seqno, const ktime_t now); | ||
49 | 65 | ||
50 | /* Subtraction a-b modulo-16, respects circular wrap-around */ | 66 | /* Subtraction a-b modulo-16, respects circular wrap-around */ |
51 | #define SUB16(a, b) (((a) + 16 - (b)) & 0xF) | 67 | #define SUB16(a, b) (((a) + 16 - (b)) & 0xF) |