diff options
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 179 | ||||
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.c | 160 | ||||
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.h | 7 |
3 files changed, 176 insertions, 170 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 52a71a900eb1..9d2e2c193cc6 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -819,167 +819,6 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) | |||
819 | return 0; | 819 | return 0; |
820 | } | 820 | } |
821 | 821 | ||
822 | /* calculate first loss interval | ||
823 | * | ||
824 | * returns estimated loss interval in usecs */ | ||
825 | |||
826 | static u32 ccid3_hc_rx_calc_first_li(struct sock *sk, | ||
827 | struct list_head *hist_list, | ||
828 | struct timeval *last_feedback, | ||
829 | u16 s, u32 bytes_recv, | ||
830 | u32 previous_x_recv) | ||
831 | { | ||
832 | struct dccp_rx_hist_entry *entry, *next, *tail = NULL; | ||
833 | u32 x_recv, p; | ||
834 | suseconds_t rtt, delta; | ||
835 | struct timeval tstamp = { 0, 0 }; | ||
836 | int interval = 0; | ||
837 | int win_count = 0; | ||
838 | int step = 0; | ||
839 | u64 fval; | ||
840 | |||
841 | list_for_each_entry_safe(entry, next, hist_list, dccphrx_node) { | ||
842 | if (dccp_rx_hist_entry_data_packet(entry)) { | ||
843 | tail = entry; | ||
844 | |||
845 | switch (step) { | ||
846 | case 0: | ||
847 | tstamp = entry->dccphrx_tstamp; | ||
848 | win_count = entry->dccphrx_ccval; | ||
849 | step = 1; | ||
850 | break; | ||
851 | case 1: | ||
852 | interval = win_count - entry->dccphrx_ccval; | ||
853 | if (interval < 0) | ||
854 | interval += TFRC_WIN_COUNT_LIMIT; | ||
855 | if (interval > 4) | ||
856 | goto found; | ||
857 | break; | ||
858 | } | ||
859 | } | ||
860 | } | ||
861 | |||
862 | if (unlikely(step == 0)) { | ||
863 | DCCP_WARN("%s(%p), packet history has no data packets!\n", | ||
864 | dccp_role(sk), sk); | ||
865 | return ~0; | ||
866 | } | ||
867 | |||
868 | if (unlikely(interval == 0)) { | ||
869 | DCCP_WARN("%s(%p), Could not find a win_count interval > 0." | ||
870 | "Defaulting to 1\n", dccp_role(sk), sk); | ||
871 | interval = 1; | ||
872 | } | ||
873 | found: | ||
874 | if (!tail) { | ||
875 | DCCP_CRIT("tail is null\n"); | ||
876 | return ~0; | ||
877 | } | ||
878 | |||
879 | delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp); | ||
880 | DCCP_BUG_ON(delta < 0); | ||
881 | |||
882 | rtt = delta * 4 / interval; | ||
883 | ccid3_pr_debug("%s(%p), approximated RTT to %dus\n", | ||
884 | dccp_role(sk), sk, (int)rtt); | ||
885 | |||
886 | /* | ||
887 | * Determine the length of the first loss interval via inverse lookup. | ||
888 | * Assume that X_recv can be computed by the throughput equation | ||
889 | * s | ||
890 | * X_recv = -------- | ||
891 | * R * fval | ||
892 | * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1]. | ||
893 | */ | ||
894 | if (rtt == 0) { /* would result in divide-by-zero */ | ||
895 | DCCP_WARN("RTT==0\n"); | ||
896 | return ~0; | ||
897 | } | ||
898 | |||
899 | dccp_timestamp(sk, &tstamp); | ||
900 | delta = timeval_delta(&tstamp, last_feedback); | ||
901 | DCCP_BUG_ON(delta <= 0); | ||
902 | |||
903 | x_recv = scaled_div32(bytes_recv, delta); | ||
904 | if (x_recv == 0) { /* would also trigger divide-by-zero */ | ||
905 | DCCP_WARN("X_recv==0\n"); | ||
906 | if (previous_x_recv == 0) { | ||
907 | DCCP_BUG("stored value of X_recv is zero"); | ||
908 | return ~0; | ||
909 | } | ||
910 | x_recv = previous_x_recv; | ||
911 | } | ||
912 | |||
913 | fval = scaled_div(s, rtt); | ||
914 | fval = scaled_div32(fval, x_recv); | ||
915 | p = tfrc_calc_x_reverse_lookup(fval); | ||
916 | |||
917 | ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied " | ||
918 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); | ||
919 | |||
920 | if (p == 0) | ||
921 | return ~0; | ||
922 | else | ||
923 | return 1000000 / p; | ||
924 | } | ||
925 | |||
926 | static void ccid3_hc_rx_update_li(struct sock *sk, | ||
927 | struct dccp_li_hist *li_hist, | ||
928 | struct list_head *li_hist_list, | ||
929 | struct list_head *hist_list, | ||
930 | struct timeval *last_feedback, | ||
931 | u16 s, u32 bytes_recv, | ||
932 | u32 previous_x_recv, | ||
933 | u64 seq_loss, u8 win_loss) | ||
934 | { | ||
935 | struct dccp_li_hist_entry *head; | ||
936 | u64 seq_temp; | ||
937 | |||
938 | if (list_empty(li_hist_list)) { | ||
939 | if (!dccp_li_hist_interval_new(li_hist, li_hist_list, | ||
940 | seq_loss, win_loss)) | ||
941 | return; | ||
942 | |||
943 | head = list_entry(li_hist_list->next, struct dccp_li_hist_entry, | ||
944 | dccplih_node); | ||
945 | head->dccplih_interval = | ||
946 | ccid3_hc_rx_calc_first_li(sk, hist_list, | ||
947 | last_feedback, s, | ||
948 | bytes_recv, | ||
949 | previous_x_recv); | ||
950 | } else { | ||
951 | struct dccp_li_hist_entry *entry; | ||
952 | struct list_head *tail; | ||
953 | |||
954 | head = list_entry(li_hist_list->next, struct dccp_li_hist_entry, | ||
955 | dccplih_node); | ||
956 | /* FIXME win count check removed as was wrong */ | ||
957 | /* should make this check with receive history */ | ||
958 | /* and compare there as per section 10.2 of RFC4342 */ | ||
959 | |||
960 | /* new loss event detected */ | ||
961 | /* calculate last interval length */ | ||
962 | seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss); | ||
963 | entry = dccp_li_hist_entry_new(li_hist, GFP_ATOMIC); | ||
964 | |||
965 | if (entry == NULL) { | ||
966 | DCCP_BUG("out of memory - can not allocate entry"); | ||
967 | return; | ||
968 | } | ||
969 | |||
970 | list_add(&entry->dccplih_node, li_hist_list); | ||
971 | |||
972 | tail = li_hist_list->prev; | ||
973 | list_del(tail); | ||
974 | kmem_cache_free(li_hist->dccplih_slab, tail); | ||
975 | |||
976 | /* Create the newest interval */ | ||
977 | entry->dccplih_seqno = seq_loss; | ||
978 | entry->dccplih_interval = seq_temp; | ||
979 | entry->dccplih_win_count = win_loss; | ||
980 | } | ||
981 | } | ||
982 | |||
983 | static int ccid3_hc_rx_detect_loss(struct sock *sk, | 822 | static int ccid3_hc_rx_detect_loss(struct sock *sk, |
984 | struct dccp_rx_hist_entry *packet) | 823 | struct dccp_rx_hist_entry *packet) |
985 | { | 824 | { |
@@ -1005,15 +844,15 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk, | |||
1005 | while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) | 844 | while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) |
1006 | > TFRC_RECV_NUM_LATE_LOSS) { | 845 | > TFRC_RECV_NUM_LATE_LOSS) { |
1007 | loss = 1; | 846 | loss = 1; |
1008 | ccid3_hc_rx_update_li(sk, ccid3_li_hist, | 847 | dccp_li_update_li(sk, ccid3_li_hist, |
1009 | &hcrx->ccid3hcrx_li_hist, | 848 | &hcrx->ccid3hcrx_li_hist, |
1010 | &hcrx->ccid3hcrx_hist, | 849 | &hcrx->ccid3hcrx_hist, |
1011 | &hcrx->ccid3hcrx_tstamp_last_feedback, | 850 | &hcrx->ccid3hcrx_tstamp_last_feedback, |
1012 | hcrx->ccid3hcrx_s, | 851 | hcrx->ccid3hcrx_s, |
1013 | hcrx->ccid3hcrx_bytes_recv, | 852 | hcrx->ccid3hcrx_bytes_recv, |
1014 | hcrx->ccid3hcrx_x_recv, | 853 | hcrx->ccid3hcrx_x_recv, |
1015 | hcrx->ccid3hcrx_seqno_nonloss, | 854 | hcrx->ccid3hcrx_seqno_nonloss, |
1016 | hcrx->ccid3hcrx_ccval_nonloss); | 855 | hcrx->ccid3hcrx_ccval_nonloss); |
1017 | tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss; | 856 | tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss; |
1018 | dccp_inc_seqno(&tmp_seqno); | 857 | dccp_inc_seqno(&tmp_seqno); |
1019 | hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; | 858 | hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; |
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 3829afc31176..ee59fde6653f 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #include <net/sock.h> | 15 | #include <net/sock.h> |
16 | #include "../../dccp.h" | 16 | #include "../../dccp.h" |
17 | #include "loss_interval.h" | 17 | #include "loss_interval.h" |
18 | #include "packet_history.h" | ||
19 | #include "tfrc.h" | ||
18 | 20 | ||
19 | struct dccp_li_hist *dccp_li_hist_new(const char *name) | 21 | struct dccp_li_hist *dccp_li_hist_new(const char *name) |
20 | { | 22 | { |
@@ -141,3 +143,161 @@ int dccp_li_hist_interval_new(struct dccp_li_hist *hist, | |||
141 | } | 143 | } |
142 | 144 | ||
143 | EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new); | 145 | EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new); |
146 | |||
147 | /* calculate first loss interval | ||
148 | * | ||
149 | * returns estimated loss interval in usecs */ | ||
150 | static u32 dccp_li_calc_first_li(struct sock *sk, | ||
151 | struct list_head *hist_list, | ||
152 | struct timeval *last_feedback, | ||
153 | u16 s, u32 bytes_recv, | ||
154 | u32 previous_x_recv) | ||
155 | { | ||
156 | struct dccp_rx_hist_entry *entry, *next, *tail = NULL; | ||
157 | u32 x_recv, p; | ||
158 | suseconds_t rtt, delta; | ||
159 | struct timeval tstamp = { 0, 0 }; | ||
160 | int interval = 0; | ||
161 | int win_count = 0; | ||
162 | int step = 0; | ||
163 | u64 fval; | ||
164 | |||
165 | list_for_each_entry_safe(entry, next, hist_list, dccphrx_node) { | ||
166 | if (dccp_rx_hist_entry_data_packet(entry)) { | ||
167 | tail = entry; | ||
168 | |||
169 | switch (step) { | ||
170 | case 0: | ||
171 | tstamp = entry->dccphrx_tstamp; | ||
172 | win_count = entry->dccphrx_ccval; | ||
173 | step = 1; | ||
174 | break; | ||
175 | case 1: | ||
176 | interval = win_count - entry->dccphrx_ccval; | ||
177 | if (interval < 0) | ||
178 | interval += TFRC_WIN_COUNT_LIMIT; | ||
179 | if (interval > 4) | ||
180 | goto found; | ||
181 | break; | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | if (unlikely(step == 0)) { | ||
187 | DCCP_WARN("%s(%p), packet history has no data packets!\n", | ||
188 | dccp_role(sk), sk); | ||
189 | return ~0; | ||
190 | } | ||
191 | |||
192 | if (unlikely(interval == 0)) { | ||
193 | DCCP_WARN("%s(%p), Could not find a win_count interval > 0." | ||
194 | "Defaulting to 1\n", dccp_role(sk), sk); | ||
195 | interval = 1; | ||
196 | } | ||
197 | found: | ||
198 | if (!tail) { | ||
199 | DCCP_CRIT("tail is null\n"); | ||
200 | return ~0; | ||
201 | } | ||
202 | |||
203 | delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp); | ||
204 | DCCP_BUG_ON(delta < 0); | ||
205 | |||
206 | rtt = delta * 4 / interval; | ||
207 | dccp_pr_debug("%s(%p), approximated RTT to %dus\n", | ||
208 | dccp_role(sk), sk, (int)rtt); | ||
209 | |||
210 | /* | ||
211 | * Determine the length of the first loss interval via inverse lookup. | ||
212 | * Assume that X_recv can be computed by the throughput equation | ||
213 | * s | ||
214 | * X_recv = -------- | ||
215 | * R * fval | ||
216 | * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1]. | ||
217 | */ | ||
218 | if (rtt == 0) { /* would result in divide-by-zero */ | ||
219 | DCCP_WARN("RTT==0\n"); | ||
220 | return ~0; | ||
221 | } | ||
222 | |||
223 | dccp_timestamp(sk, &tstamp); | ||
224 | delta = timeval_delta(&tstamp, last_feedback); | ||
225 | DCCP_BUG_ON(delta <= 0); | ||
226 | |||
227 | x_recv = scaled_div32(bytes_recv, delta); | ||
228 | if (x_recv == 0) { /* would also trigger divide-by-zero */ | ||
229 | DCCP_WARN("X_recv==0\n"); | ||
230 | if (previous_x_recv == 0) { | ||
231 | DCCP_BUG("stored value of X_recv is zero"); | ||
232 | return ~0; | ||
233 | } | ||
234 | x_recv = previous_x_recv; | ||
235 | } | ||
236 | |||
237 | fval = scaled_div(s, rtt); | ||
238 | fval = scaled_div32(fval, x_recv); | ||
239 | p = tfrc_calc_x_reverse_lookup(fval); | ||
240 | |||
241 | dccp_pr_debug("%s(%p), receive rate=%u bytes/s, implied " | ||
242 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); | ||
243 | |||
244 | if (p == 0) | ||
245 | return ~0; | ||
246 | else | ||
247 | return 1000000 / p; | ||
248 | } | ||
249 | |||
250 | void dccp_li_update_li(struct sock *sk, struct dccp_li_hist *li_hist, | ||
251 | struct list_head *li_hist_list, | ||
252 | struct list_head *hist_list, | ||
253 | struct timeval *last_feedback, u16 s, u32 bytes_recv, | ||
254 | u32 previous_x_recv, u64 seq_loss, u8 win_loss) | ||
255 | { | ||
256 | struct dccp_li_hist_entry *head; | ||
257 | u64 seq_temp; | ||
258 | |||
259 | if (list_empty(li_hist_list)) { | ||
260 | if (!dccp_li_hist_interval_new(li_hist, li_hist_list, | ||
261 | seq_loss, win_loss)) | ||
262 | return; | ||
263 | |||
264 | head = list_entry(li_hist_list->next, struct dccp_li_hist_entry, | ||
265 | dccplih_node); | ||
266 | head->dccplih_interval = dccp_li_calc_first_li(sk, hist_list, | ||
267 | last_feedback, | ||
268 | s, bytes_recv, | ||
269 | previous_x_recv); | ||
270 | } else { | ||
271 | struct dccp_li_hist_entry *entry; | ||
272 | struct list_head *tail; | ||
273 | |||
274 | head = list_entry(li_hist_list->next, struct dccp_li_hist_entry, | ||
275 | dccplih_node); | ||
276 | /* FIXME win count check removed as was wrong */ | ||
277 | /* should make this check with receive history */ | ||
278 | /* and compare there as per section 10.2 of RFC4342 */ | ||
279 | |||
280 | /* new loss event detected */ | ||
281 | /* calculate last interval length */ | ||
282 | seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss); | ||
283 | entry = dccp_li_hist_entry_new(li_hist, GFP_ATOMIC); | ||
284 | |||
285 | if (entry == NULL) { | ||
286 | DCCP_BUG("out of memory - can not allocate entry"); | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | list_add(&entry->dccplih_node, li_hist_list); | ||
291 | |||
292 | tail = li_hist_list->prev; | ||
293 | list_del(tail); | ||
294 | kmem_cache_free(li_hist->dccplih_slab, tail); | ||
295 | |||
296 | /* Create the newest interval */ | ||
297 | entry->dccplih_seqno = seq_loss; | ||
298 | entry->dccplih_interval = seq_temp; | ||
299 | entry->dccplih_win_count = win_loss; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | EXPORT_SYMBOL_GPL(dccp_li_update_li); | ||
diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h index 1e48fe323006..17f173a30055 100644 --- a/net/dccp/ccids/lib/loss_interval.h +++ b/net/dccp/ccids/lib/loss_interval.h | |||
@@ -54,4 +54,11 @@ extern u32 dccp_li_hist_calc_i_mean(struct list_head *list); | |||
54 | 54 | ||
55 | extern int dccp_li_hist_interval_new(struct dccp_li_hist *hist, | 55 | extern int dccp_li_hist_interval_new(struct dccp_li_hist *hist, |
56 | struct list_head *list, const u64 seq_loss, const u8 win_loss); | 56 | struct list_head *list, const u64 seq_loss, const u8 win_loss); |
57 | |||
58 | extern void dccp_li_update_li(struct sock *sk, struct dccp_li_hist *li_hist, | ||
59 | struct list_head *li_hist_list, | ||
60 | struct list_head *hist_list, | ||
61 | struct timeval *last_feedback, u16 s, | ||
62 | u32 bytes_recv, u32 previous_x_recv, | ||
63 | u64 seq_loss, u8 win_loss); | ||
57 | #endif /* _DCCP_LI_HIST_ */ | 64 | #endif /* _DCCP_LI_HIST_ */ |