diff options
Diffstat (limited to 'net/dccp/ccids/ccid3.c')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 8266dfde89c1..8f112d18d450 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * net/dccp/ccids/ccid3.c | 2 | * net/dccp/ccids/ccid3.c |
3 | * | 3 | * |
4 | * Copyright (c) 2007 The University of Aberdeen, Scotland, UK | ||
4 | * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. | 5 | * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. |
5 | * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> | 6 | * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> |
6 | * | 7 | * |
@@ -33,11 +34,7 @@ | |||
33 | * along with this program; if not, write to the Free Software | 34 | * along with this program; if not, write to the Free Software |
34 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 35 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
35 | */ | 36 | */ |
36 | #include "../ccid.h" | ||
37 | #include "../dccp.h" | 37 | #include "../dccp.h" |
38 | #include "lib/packet_history.h" | ||
39 | #include "lib/loss_interval.h" | ||
40 | #include "lib/tfrc.h" | ||
41 | #include "ccid3.h" | 38 | #include "ccid3.h" |
42 | 39 | ||
43 | #include <asm/unaligned.h> | 40 | #include <asm/unaligned.h> |
@@ -757,6 +754,46 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) | |||
757 | return 0; | 754 | return 0; |
758 | } | 755 | } |
759 | 756 | ||
757 | /** ccid3_first_li - Implements [RFC 3448, 6.3.1] | ||
758 | * | ||
759 | * Determine the length of the first loss interval via inverse lookup. | ||
760 | * Assume that X_recv can be computed by the throughput equation | ||
761 | * s | ||
762 | * X_recv = -------- | ||
763 | * R * fval | ||
764 | * Find some p such that f(p) = fval; return 1/p (scaled). | ||
765 | */ | ||
766 | static u32 ccid3_first_li(struct sock *sk) | ||
767 | { | ||
768 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | ||
769 | u32 x_recv, p, delta; | ||
770 | u64 fval; | ||
771 | |||
772 | if (hcrx->ccid3hcrx_rtt == 0) { | ||
773 | DCCP_WARN("No RTT estimate available, using fallback RTT\n"); | ||
774 | hcrx->ccid3hcrx_rtt = DCCP_FALLBACK_RTT; | ||
775 | } | ||
776 | |||
777 | delta = ktime_to_us(net_timedelta(hcrx->ccid3hcrx_tstamp_last_feedback)); | ||
778 | x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta); | ||
779 | if (x_recv == 0) { /* would also trigger divide-by-zero */ | ||
780 | DCCP_WARN("X_recv==0\n"); | ||
781 | if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) { | ||
782 | DCCP_BUG("stored value of X_recv is zero"); | ||
783 | return ~0U; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | fval = scaled_div(hcrx->ccid3hcrx_s, hcrx->ccid3hcrx_rtt); | ||
788 | fval = scaled_div32(fval, x_recv); | ||
789 | p = tfrc_calc_x_reverse_lookup(fval); | ||
790 | |||
791 | ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied " | ||
792 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); | ||
793 | |||
794 | return p == 0 ? ~0U : scaled_div(1, p); | ||
795 | } | ||
796 | |||
760 | static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | 797 | static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) |
761 | { | 798 | { |
762 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | 799 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); |
@@ -794,6 +831,14 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
794 | /* | 831 | /* |
795 | * Handle pending losses and otherwise check for new loss | 832 | * Handle pending losses and otherwise check for new loss |
796 | */ | 833 | */ |
834 | if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist) && | ||
835 | tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, | ||
836 | &hcrx->ccid3hcrx_li_hist, | ||
837 | skb, ndp, ccid3_first_li, sk) ) { | ||
838 | do_feedback = CCID3_FBACK_PARAM_CHANGE; | ||
839 | goto done_receiving; | ||
840 | } | ||
841 | |||
797 | if (tfrc_rx_hist_new_loss_indicated(&hcrx->ccid3hcrx_hist, skb, ndp)) | 842 | if (tfrc_rx_hist_new_loss_indicated(&hcrx->ccid3hcrx_hist, skb, ndp)) |
798 | goto update_records; | 843 | goto update_records; |
799 | 844 | ||
@@ -803,7 +848,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
803 | if (unlikely(!is_data_packet)) | 848 | if (unlikely(!is_data_packet)) |
804 | goto update_records; | 849 | goto update_records; |
805 | 850 | ||
806 | if (list_empty(&hcrx->ccid3hcrx_li_hist)) { /* no loss so far: p = 0 */ | 851 | if (!tfrc_lh_is_initialised(&hcrx->ccid3hcrx_li_hist)) { |
807 | const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->ccid3hcrx_hist, skb); | 852 | const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->ccid3hcrx_hist, skb); |
808 | /* | 853 | /* |
809 | * Empty loss history: no loss so far, hence p stays 0. | 854 | * Empty loss history: no loss so far, hence p stays 0. |
@@ -812,6 +857,13 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
812 | */ | 857 | */ |
813 | if (sample != 0) | 858 | if (sample != 0) |
814 | hcrx->ccid3hcrx_rtt = tfrc_ewma(hcrx->ccid3hcrx_rtt, sample, 9); | 859 | hcrx->ccid3hcrx_rtt = tfrc_ewma(hcrx->ccid3hcrx_rtt, sample, 9); |
860 | |||
861 | } else if (tfrc_lh_update_i_mean(&hcrx->ccid3hcrx_li_hist, skb)) { | ||
862 | /* | ||
863 | * Step (3) of [RFC 3448, 6.1]: Recompute I_mean and, if I_mean | ||
864 | * has decreased (resp. p has increased), send feedback now. | ||
865 | */ | ||
866 | do_feedback = CCID3_FBACK_PARAM_CHANGE; | ||
815 | } | 867 | } |
816 | 868 | ||
817 | /* | 869 | /* |
@@ -823,6 +875,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
823 | update_records: | 875 | update_records: |
824 | tfrc_rx_hist_add_packet(&hcrx->ccid3hcrx_hist, skb, ndp); | 876 | tfrc_rx_hist_add_packet(&hcrx->ccid3hcrx_hist, skb, ndp); |
825 | 877 | ||
878 | done_receiving: | ||
826 | if (do_feedback) | 879 | if (do_feedback) |
827 | ccid3_hc_rx_send_feedback(sk, skb, do_feedback); | 880 | ccid3_hc_rx_send_feedback(sk, skb, do_feedback); |
828 | } | 881 | } |
@@ -831,10 +884,8 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk) | |||
831 | { | 884 | { |
832 | struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid); | 885 | struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid); |
833 | 886 | ||
834 | ccid3_pr_debug("entry\n"); | ||
835 | |||
836 | hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; | 887 | hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; |
837 | INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); | 888 | tfrc_lh_init(&hcrx->ccid3hcrx_li_hist); |
838 | return tfrc_rx_hist_alloc(&hcrx->ccid3hcrx_hist); | 889 | return tfrc_rx_hist_alloc(&hcrx->ccid3hcrx_hist); |
839 | } | 890 | } |
840 | 891 | ||
@@ -844,11 +895,8 @@ static void ccid3_hc_rx_exit(struct sock *sk) | |||
844 | 895 | ||
845 | ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM); | 896 | ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM); |
846 | 897 | ||
847 | /* Empty packet history */ | ||
848 | tfrc_rx_hist_purge(&hcrx->ccid3hcrx_hist); | 898 | tfrc_rx_hist_purge(&hcrx->ccid3hcrx_hist); |
849 | 899 | tfrc_lh_cleanup(&hcrx->ccid3hcrx_li_hist); | |
850 | /* Empty loss interval history */ | ||
851 | dccp_li_hist_purge(&hcrx->ccid3hcrx_li_hist); | ||
852 | } | 900 | } |
853 | 901 | ||
854 | static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) | 902 | static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) |