diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2006-12-09 21:03:30 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-11 17:34:44 -0500 |
commit | bfe24a6cc222d27e1491f850802fa6932232b8ef (patch) | |
tree | a1782cdb20b19ffb07e1e7ce1ab7aba34fddcecd /net/dccp | |
parent | b9039a2a8df974d7702564318722434bb276a995 (diff) |
[DCCP] ccid3: Simplify calculation for reverse lookup of p
This simplifies the calculation of a value p for a given fval when the
first loss interval is computed (RFC 3448, 6.3.1). It makes use of the
two new functions scaled_div/scaled_div32 to provide overflow protection.
Additionally, protection against divide-by-zero is extended - in this
case the function will return the maximally possible value of p=100%.
Background:
The maximum fval, f(100%), is approximately 244, i.e. the scaled value of fval
should never exceed 244E6, which fits easily into u32. The problem is the scaling
by 10^6, since additionally R(TT) is in microseconds.
This is resolved by breaking the division into two stages: the first stage
computes fval=(s*10^6)/R, stores that into u64; the second stage computes
fval = (fval*10^6)/X_recv and complains if overflow is reached for u32.
This case is safe since the TFRC reverse-lookup routine then returns p=100%.
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')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index bdd13de4f422..89ef1183e48c 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -785,12 +785,12 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) | |||
785 | { | 785 | { |
786 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | 786 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); |
787 | struct dccp_rx_hist_entry *entry, *next, *tail = NULL; | 787 | struct dccp_rx_hist_entry *entry, *next, *tail = NULL; |
788 | u32 rtt, delta, x_recv, fval, p, tmp2; | 788 | u32 rtt, delta, x_recv, p; |
789 | struct timeval tstamp = { 0, }; | 789 | struct timeval tstamp = { 0, }; |
790 | int interval = 0; | 790 | int interval = 0; |
791 | int win_count = 0; | 791 | int win_count = 0; |
792 | int step = 0; | 792 | int step = 0; |
793 | u64 tmp1; | 793 | u64 fval; |
794 | 794 | ||
795 | list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, | 795 | list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, |
796 | dccphrx_node) { | 796 | dccphrx_node) { |
@@ -834,30 +834,35 @@ found: | |||
834 | ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n", | 834 | ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n", |
835 | dccp_role(sk), sk, rtt); | 835 | dccp_role(sk), sk, rtt); |
836 | 836 | ||
837 | if (rtt == 0) { | 837 | /* |
838 | DCCP_WARN("RTT==0, setting to 1\n"); | 838 | * Determine the length of the first loss interval via inverse lookup. |
839 | rtt = 1; | 839 | * Assume that X_recv can be computed by the throughput equation |
840 | * s | ||
841 | * X_recv = -------- | ||
842 | * R * fval | ||
843 | * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1]. | ||
844 | */ | ||
845 | if (rtt == 0) { /* would result in divide-by-zero */ | ||
846 | DCCP_WARN("RTT==0, returning 1/p = 1\n"); | ||
847 | return 1000000; | ||
840 | } | 848 | } |
841 | 849 | ||
842 | dccp_timestamp(sk, &tstamp); | 850 | dccp_timestamp(sk, &tstamp); |
843 | delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback); | 851 | delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback); |
844 | x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta); | 852 | x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta); |
845 | 853 | ||
846 | if (x_recv == 0) | 854 | if (x_recv == 0) { /* would also trigger divide-by-zero */ |
847 | x_recv = hcrx->ccid3hcrx_x_recv; | 855 | DCCP_WARN("X_recv==0\n"); |
848 | 856 | if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) { | |
849 | tmp1 = (u64)x_recv * (u64)rtt; | 857 | DCCP_BUG("stored value of X_recv is zero"); |
850 | do_div(tmp1,10000000); | 858 | return 1000000; |
851 | tmp2 = (u32)tmp1; | 859 | } |
852 | |||
853 | if (!tmp2) { | ||
854 | DCCP_CRIT("tmp2 = 0, x_recv = %u, rtt =%u\n", x_recv, rtt); | ||
855 | return ~0; | ||
856 | } | 860 | } |
857 | 861 | ||
858 | fval = (hcrx->ccid3hcrx_s * 100000) / tmp2; | 862 | fval = scaled_div(hcrx->ccid3hcrx_s, rtt); |
859 | /* do not alter order above or you will get overflow on 32 bit */ | 863 | fval = scaled_div32(fval, x_recv); |
860 | p = tfrc_calc_x_reverse_lookup(fval); | 864 | p = tfrc_calc_x_reverse_lookup(fval); |
865 | |||
861 | ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied " | 866 | ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied " |
862 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); | 867 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); |
863 | 868 | ||