diff options
Diffstat (limited to 'net/dccp/ccids')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 212 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.h | 5 | ||||
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.c | 246 | ||||
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.h | 46 |
4 files changed, 237 insertions, 272 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index ec7fa4d67f08..e91c2b9dc27b 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * net/dccp/ccids/ccid3.c | 2 | * net/dccp/ccids/ccid3.c |
3 | * | 3 | * |
4 | * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. | 4 | * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. |
5 | * Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz> | 5 | * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> |
6 | * | 6 | * |
7 | * An implementation of the DCCP protocol | 7 | * An implementation of the DCCP protocol |
8 | * | 8 | * |
@@ -49,7 +49,6 @@ static int ccid3_debug; | |||
49 | 49 | ||
50 | static struct dccp_tx_hist *ccid3_tx_hist; | 50 | static struct dccp_tx_hist *ccid3_tx_hist; |
51 | static struct dccp_rx_hist *ccid3_rx_hist; | 51 | static struct dccp_rx_hist *ccid3_rx_hist; |
52 | static struct dccp_li_hist *ccid3_li_hist; | ||
53 | 52 | ||
54 | /* | 53 | /* |
55 | * Transmitter Half-Connection Routines | 54 | * Transmitter Half-Connection Routines |
@@ -194,25 +193,20 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) | |||
194 | * The algorithm is not applicable if RTT < 4 microseconds. | 193 | * The algorithm is not applicable if RTT < 4 microseconds. |
195 | */ | 194 | */ |
196 | static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx, | 195 | static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx, |
197 | struct timeval *now) | 196 | ktime_t now) |
198 | { | 197 | { |
199 | suseconds_t delta; | ||
200 | u32 quarter_rtts; | 198 | u32 quarter_rtts; |
201 | 199 | ||
202 | if (unlikely(hctx->ccid3hctx_rtt < 4)) /* avoid divide-by-zero */ | 200 | if (unlikely(hctx->ccid3hctx_rtt < 4)) /* avoid divide-by-zero */ |
203 | return; | 201 | return; |
204 | 202 | ||
205 | delta = timeval_delta(now, &hctx->ccid3hctx_t_last_win_count); | 203 | quarter_rtts = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count); |
206 | DCCP_BUG_ON(delta < 0); | 204 | quarter_rtts /= hctx->ccid3hctx_rtt / 4; |
207 | |||
208 | quarter_rtts = (u32)delta / (hctx->ccid3hctx_rtt / 4); | ||
209 | 205 | ||
210 | if (quarter_rtts > 0) { | 206 | if (quarter_rtts > 0) { |
211 | hctx->ccid3hctx_t_last_win_count = *now; | 207 | hctx->ccid3hctx_t_last_win_count = now; |
212 | hctx->ccid3hctx_last_win_count += min_t(u32, quarter_rtts, 5); | 208 | hctx->ccid3hctx_last_win_count += min_t(u32, quarter_rtts, 5); |
213 | hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */ | 209 | hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */ |
214 | |||
215 | ccid3_pr_debug("now at %#X\n", hctx->ccid3hctx_last_win_count); | ||
216 | } | 210 | } |
217 | } | 211 | } |
218 | 212 | ||
@@ -312,8 +306,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
312 | { | 306 | { |
313 | struct dccp_sock *dp = dccp_sk(sk); | 307 | struct dccp_sock *dp = dccp_sk(sk); |
314 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | 308 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); |
315 | struct timeval now; | 309 | ktime_t now = ktime_get_real(); |
316 | suseconds_t delay; | 310 | s64 delay; |
317 | 311 | ||
318 | BUG_ON(hctx == NULL); | 312 | BUG_ON(hctx == NULL); |
319 | 313 | ||
@@ -325,8 +319,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
325 | if (unlikely(skb->len == 0)) | 319 | if (unlikely(skb->len == 0)) |
326 | return -EBADMSG; | 320 | return -EBADMSG; |
327 | 321 | ||
328 | dccp_timestamp(sk, &now); | ||
329 | |||
330 | switch (hctx->ccid3hctx_state) { | 322 | switch (hctx->ccid3hctx_state) { |
331 | case TFRC_SSTATE_NO_SENT: | 323 | case TFRC_SSTATE_NO_SENT: |
332 | sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, | 324 | sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, |
@@ -349,7 +341,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
349 | ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt); | 341 | ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt); |
350 | hctx->ccid3hctx_rtt = dp->dccps_syn_rtt; | 342 | hctx->ccid3hctx_rtt = dp->dccps_syn_rtt; |
351 | hctx->ccid3hctx_x = rfc3390_initial_rate(sk); | 343 | hctx->ccid3hctx_x = rfc3390_initial_rate(sk); |
352 | hctx->ccid3hctx_t_ld = now; | 344 | hctx->ccid3hctx_t_ld = ktime_to_timeval(now); |
353 | } else { | 345 | } else { |
354 | /* Sender does not have RTT sample: X = MSS/second */ | 346 | /* Sender does not have RTT sample: X = MSS/second */ |
355 | hctx->ccid3hctx_x = dp->dccps_mss_cache; | 347 | hctx->ccid3hctx_x = dp->dccps_mss_cache; |
@@ -361,7 +353,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
361 | break; | 353 | break; |
362 | case TFRC_SSTATE_NO_FBACK: | 354 | case TFRC_SSTATE_NO_FBACK: |
363 | case TFRC_SSTATE_FBACK: | 355 | case TFRC_SSTATE_FBACK: |
364 | delay = timeval_delta(&hctx->ccid3hctx_t_nom, &now); | 356 | delay = ktime_us_delta(hctx->ccid3hctx_t_nom, now); |
365 | ccid3_pr_debug("delay=%ld\n", (long)delay); | 357 | ccid3_pr_debug("delay=%ld\n", (long)delay); |
366 | /* | 358 | /* |
367 | * Scheduling of packet transmissions [RFC 3448, 4.6] | 359 | * Scheduling of packet transmissions [RFC 3448, 4.6] |
@@ -371,10 +363,10 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
371 | * else | 363 | * else |
372 | * // send the packet in (t_nom - t_now) milliseconds. | 364 | * // send the packet in (t_nom - t_now) milliseconds. |
373 | */ | 365 | */ |
374 | if (delay - (suseconds_t)hctx->ccid3hctx_delta >= 0) | 366 | if (delay - (s64)hctx->ccid3hctx_delta >= 1000) |
375 | return delay / 1000L; | 367 | return (u32)delay / 1000L; |
376 | 368 | ||
377 | ccid3_hc_tx_update_win_count(hctx, &now); | 369 | ccid3_hc_tx_update_win_count(hctx, now); |
378 | break; | 370 | break; |
379 | case TFRC_SSTATE_TERM: | 371 | case TFRC_SSTATE_TERM: |
380 | DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk); | 372 | DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk); |
@@ -387,8 +379,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
387 | hctx->ccid3hctx_idle = 0; | 379 | hctx->ccid3hctx_idle = 0; |
388 | 380 | ||
389 | /* set the nominal send time for the next following packet */ | 381 | /* set the nominal send time for the next following packet */ |
390 | timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi); | 382 | hctx->ccid3hctx_t_nom = ktime_add_us(hctx->ccid3hctx_t_nom, |
391 | 383 | hctx->ccid3hctx_t_ipi); | |
392 | return 0; | 384 | return 0; |
393 | } | 385 | } |
394 | 386 | ||
@@ -819,154 +811,6 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) | |||
819 | return 0; | 811 | return 0; |
820 | } | 812 | } |
821 | 813 | ||
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 | { | ||
828 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | ||
829 | struct dccp_rx_hist_entry *entry, *next, *tail = NULL; | ||
830 | u32 x_recv, p; | ||
831 | suseconds_t rtt, delta; | ||
832 | struct timeval tstamp = { 0, }; | ||
833 | int interval = 0; | ||
834 | int win_count = 0; | ||
835 | int step = 0; | ||
836 | u64 fval; | ||
837 | |||
838 | list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, | ||
839 | dccphrx_node) { | ||
840 | if (dccp_rx_hist_entry_data_packet(entry)) { | ||
841 | tail = entry; | ||
842 | |||
843 | switch (step) { | ||
844 | case 0: | ||
845 | tstamp = entry->dccphrx_tstamp; | ||
846 | win_count = entry->dccphrx_ccval; | ||
847 | step = 1; | ||
848 | break; | ||
849 | case 1: | ||
850 | interval = win_count - entry->dccphrx_ccval; | ||
851 | if (interval < 0) | ||
852 | interval += TFRC_WIN_COUNT_LIMIT; | ||
853 | if (interval > 4) | ||
854 | goto found; | ||
855 | break; | ||
856 | } | ||
857 | } | ||
858 | } | ||
859 | |||
860 | if (unlikely(step == 0)) { | ||
861 | DCCP_WARN("%s(%p), packet history has no data packets!\n", | ||
862 | dccp_role(sk), sk); | ||
863 | return ~0; | ||
864 | } | ||
865 | |||
866 | if (unlikely(interval == 0)) { | ||
867 | DCCP_WARN("%s(%p), Could not find a win_count interval > 0." | ||
868 | "Defaulting to 1\n", dccp_role(sk), sk); | ||
869 | interval = 1; | ||
870 | } | ||
871 | found: | ||
872 | if (!tail) { | ||
873 | DCCP_CRIT("tail is null\n"); | ||
874 | return ~0; | ||
875 | } | ||
876 | |||
877 | delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp); | ||
878 | DCCP_BUG_ON(delta < 0); | ||
879 | |||
880 | rtt = delta * 4 / interval; | ||
881 | ccid3_pr_debug("%s(%p), approximated RTT to %dus\n", | ||
882 | dccp_role(sk), sk, (int)rtt); | ||
883 | |||
884 | /* | ||
885 | * Determine the length of the first loss interval via inverse lookup. | ||
886 | * Assume that X_recv can be computed by the throughput equation | ||
887 | * s | ||
888 | * X_recv = -------- | ||
889 | * R * fval | ||
890 | * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1]. | ||
891 | */ | ||
892 | if (rtt == 0) { /* would result in divide-by-zero */ | ||
893 | DCCP_WARN("RTT==0\n"); | ||
894 | return ~0; | ||
895 | } | ||
896 | |||
897 | dccp_timestamp(sk, &tstamp); | ||
898 | delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback); | ||
899 | DCCP_BUG_ON(delta <= 0); | ||
900 | |||
901 | x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta); | ||
902 | if (x_recv == 0) { /* would also trigger divide-by-zero */ | ||
903 | DCCP_WARN("X_recv==0\n"); | ||
904 | if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) { | ||
905 | DCCP_BUG("stored value of X_recv is zero"); | ||
906 | return ~0; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | fval = scaled_div(hcrx->ccid3hcrx_s, rtt); | ||
911 | fval = scaled_div32(fval, x_recv); | ||
912 | p = tfrc_calc_x_reverse_lookup(fval); | ||
913 | |||
914 | ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied " | ||
915 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); | ||
916 | |||
917 | if (p == 0) | ||
918 | return ~0; | ||
919 | else | ||
920 | return 1000000 / p; | ||
921 | } | ||
922 | |||
923 | static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) | ||
924 | { | ||
925 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | ||
926 | struct dccp_li_hist_entry *head; | ||
927 | u64 seq_temp; | ||
928 | |||
929 | if (list_empty(&hcrx->ccid3hcrx_li_hist)) { | ||
930 | if (!dccp_li_hist_interval_new(ccid3_li_hist, | ||
931 | &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss)) | ||
932 | return; | ||
933 | |||
934 | head = list_entry(hcrx->ccid3hcrx_li_hist.next, | ||
935 | struct dccp_li_hist_entry, dccplih_node); | ||
936 | head->dccplih_interval = ccid3_hc_rx_calc_first_li(sk); | ||
937 | } else { | ||
938 | struct dccp_li_hist_entry *entry; | ||
939 | struct list_head *tail; | ||
940 | |||
941 | head = list_entry(hcrx->ccid3hcrx_li_hist.next, | ||
942 | struct dccp_li_hist_entry, dccplih_node); | ||
943 | /* FIXME win count check removed as was wrong */ | ||
944 | /* should make this check with receive history */ | ||
945 | /* and compare there as per section 10.2 of RFC4342 */ | ||
946 | |||
947 | /* new loss event detected */ | ||
948 | /* calculate last interval length */ | ||
949 | seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss); | ||
950 | entry = dccp_li_hist_entry_new(ccid3_li_hist, GFP_ATOMIC); | ||
951 | |||
952 | if (entry == NULL) { | ||
953 | DCCP_BUG("out of memory - can not allocate entry"); | ||
954 | return; | ||
955 | } | ||
956 | |||
957 | list_add(&entry->dccplih_node, &hcrx->ccid3hcrx_li_hist); | ||
958 | |||
959 | tail = hcrx->ccid3hcrx_li_hist.prev; | ||
960 | list_del(tail); | ||
961 | kmem_cache_free(ccid3_li_hist->dccplih_slab, tail); | ||
962 | |||
963 | /* Create the newest interval */ | ||
964 | entry->dccplih_seqno = seq_loss; | ||
965 | entry->dccplih_interval = seq_temp; | ||
966 | entry->dccplih_win_count = win_loss; | ||
967 | } | ||
968 | } | ||
969 | |||
970 | static int ccid3_hc_rx_detect_loss(struct sock *sk, | 814 | static int ccid3_hc_rx_detect_loss(struct sock *sk, |
971 | struct dccp_rx_hist_entry *packet) | 815 | struct dccp_rx_hist_entry *packet) |
972 | { | 816 | { |
@@ -992,8 +836,15 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk, | |||
992 | while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) | 836 | while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) |
993 | > TFRC_RECV_NUM_LATE_LOSS) { | 837 | > TFRC_RECV_NUM_LATE_LOSS) { |
994 | loss = 1; | 838 | loss = 1; |
995 | ccid3_hc_rx_update_li(sk, hcrx->ccid3hcrx_seqno_nonloss, | 839 | dccp_li_update_li(sk, |
996 | hcrx->ccid3hcrx_ccval_nonloss); | 840 | &hcrx->ccid3hcrx_li_hist, |
841 | &hcrx->ccid3hcrx_hist, | ||
842 | &hcrx->ccid3hcrx_tstamp_last_feedback, | ||
843 | hcrx->ccid3hcrx_s, | ||
844 | hcrx->ccid3hcrx_bytes_recv, | ||
845 | hcrx->ccid3hcrx_x_recv, | ||
846 | hcrx->ccid3hcrx_seqno_nonloss, | ||
847 | hcrx->ccid3hcrx_ccval_nonloss); | ||
997 | tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss; | 848 | tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss; |
998 | dccp_inc_seqno(&tmp_seqno); | 849 | dccp_inc_seqno(&tmp_seqno); |
999 | hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; | 850 | hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; |
@@ -1152,7 +1003,7 @@ static void ccid3_hc_rx_exit(struct sock *sk) | |||
1152 | dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist); | 1003 | dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist); |
1153 | 1004 | ||
1154 | /* Empty loss interval history */ | 1005 | /* Empty loss interval history */ |
1155 | dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist); | 1006 | dccp_li_hist_purge(&hcrx->ccid3hcrx_li_hist); |
1156 | } | 1007 | } |
1157 | 1008 | ||
1158 | static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) | 1009 | static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) |
@@ -1236,19 +1087,12 @@ static __init int ccid3_module_init(void) | |||
1236 | if (ccid3_tx_hist == NULL) | 1087 | if (ccid3_tx_hist == NULL) |
1237 | goto out_free_rx; | 1088 | goto out_free_rx; |
1238 | 1089 | ||
1239 | ccid3_li_hist = dccp_li_hist_new("ccid3"); | ||
1240 | if (ccid3_li_hist == NULL) | ||
1241 | goto out_free_tx; | ||
1242 | |||
1243 | rc = ccid_register(&ccid3); | 1090 | rc = ccid_register(&ccid3); |
1244 | if (rc != 0) | 1091 | if (rc != 0) |
1245 | goto out_free_loss_interval_history; | 1092 | goto out_free_tx; |
1246 | out: | 1093 | out: |
1247 | return rc; | 1094 | return rc; |
1248 | 1095 | ||
1249 | out_free_loss_interval_history: | ||
1250 | dccp_li_hist_delete(ccid3_li_hist); | ||
1251 | ccid3_li_hist = NULL; | ||
1252 | out_free_tx: | 1096 | out_free_tx: |
1253 | dccp_tx_hist_delete(ccid3_tx_hist); | 1097 | dccp_tx_hist_delete(ccid3_tx_hist); |
1254 | ccid3_tx_hist = NULL; | 1098 | ccid3_tx_hist = NULL; |
@@ -1271,10 +1115,6 @@ static __exit void ccid3_module_exit(void) | |||
1271 | dccp_rx_hist_delete(ccid3_rx_hist); | 1115 | dccp_rx_hist_delete(ccid3_rx_hist); |
1272 | ccid3_rx_hist = NULL; | 1116 | ccid3_rx_hist = NULL; |
1273 | } | 1117 | } |
1274 | if (ccid3_li_hist != NULL) { | ||
1275 | dccp_li_hist_delete(ccid3_li_hist); | ||
1276 | ccid3_li_hist = NULL; | ||
1277 | } | ||
1278 | } | 1118 | } |
1279 | module_exit(ccid3_module_exit); | 1119 | module_exit(ccid3_module_exit); |
1280 | 1120 | ||
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 8d31b389c19c..51d4b804e334 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h | |||
@@ -36,6 +36,7 @@ | |||
36 | #ifndef _DCCP_CCID3_H_ | 36 | #ifndef _DCCP_CCID3_H_ |
37 | #define _DCCP_CCID3_H_ | 37 | #define _DCCP_CCID3_H_ |
38 | 38 | ||
39 | #include <linux/ktime.h> | ||
39 | #include <linux/list.h> | 40 | #include <linux/list.h> |
40 | #include <linux/time.h> | 41 | #include <linux/time.h> |
41 | #include <linux/types.h> | 42 | #include <linux/types.h> |
@@ -108,10 +109,10 @@ struct ccid3_hc_tx_sock { | |||
108 | enum ccid3_hc_tx_states ccid3hctx_state:8; | 109 | enum ccid3_hc_tx_states ccid3hctx_state:8; |
109 | u8 ccid3hctx_last_win_count; | 110 | u8 ccid3hctx_last_win_count; |
110 | u8 ccid3hctx_idle; | 111 | u8 ccid3hctx_idle; |
111 | struct timeval ccid3hctx_t_last_win_count; | 112 | ktime_t ccid3hctx_t_last_win_count; |
112 | struct timer_list ccid3hctx_no_feedback_timer; | 113 | struct timer_list ccid3hctx_no_feedback_timer; |
113 | struct timeval ccid3hctx_t_ld; | 114 | struct timeval ccid3hctx_t_ld; |
114 | struct timeval ccid3hctx_t_nom; | 115 | ktime_t ccid3hctx_t_nom; |
115 | u32 ccid3hctx_delta; | 116 | u32 ccid3hctx_delta; |
116 | struct list_head ccid3hctx_hist; | 117 | struct list_head ccid3hctx_hist; |
117 | struct ccid3_options_received ccid3hctx_options_received; | 118 | struct ccid3_options_received ccid3hctx_options_received; |
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c index 372d7e75cdd8..515225f3a464 100644 --- a/net/dccp/ccids/lib/loss_interval.c +++ b/net/dccp/ccids/lib/loss_interval.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * net/dccp/ccids/lib/loss_interval.c | 2 | * net/dccp/ccids/lib/loss_interval.c |
3 | * | 3 | * |
4 | * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. | 4 | * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. |
5 | * Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz> | 5 | * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> |
6 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 6 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -15,58 +15,38 @@ | |||
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 | #define DCCP_LI_HIST_IVAL_F_LENGTH 8 |
20 | { | ||
21 | struct dccp_li_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC); | ||
22 | static const char dccp_li_hist_mask[] = "li_hist_%s"; | ||
23 | char *slab_name; | ||
24 | |||
25 | if (hist == NULL) | ||
26 | goto out; | ||
27 | |||
28 | slab_name = kmalloc(strlen(name) + sizeof(dccp_li_hist_mask) - 1, | ||
29 | GFP_ATOMIC); | ||
30 | if (slab_name == NULL) | ||
31 | goto out_free_hist; | ||
32 | |||
33 | sprintf(slab_name, dccp_li_hist_mask, name); | ||
34 | hist->dccplih_slab = kmem_cache_create(slab_name, | ||
35 | sizeof(struct dccp_li_hist_entry), | ||
36 | 0, SLAB_HWCACHE_ALIGN, | ||
37 | NULL, NULL); | ||
38 | if (hist->dccplih_slab == NULL) | ||
39 | goto out_free_slab_name; | ||
40 | out: | ||
41 | return hist; | ||
42 | out_free_slab_name: | ||
43 | kfree(slab_name); | ||
44 | out_free_hist: | ||
45 | kfree(hist); | ||
46 | hist = NULL; | ||
47 | goto out; | ||
48 | } | ||
49 | 22 | ||
50 | EXPORT_SYMBOL_GPL(dccp_li_hist_new); | 23 | struct dccp_li_hist_entry { |
24 | struct list_head dccplih_node; | ||
25 | u64 dccplih_seqno:48, | ||
26 | dccplih_win_count:4; | ||
27 | u32 dccplih_interval; | ||
28 | }; | ||
51 | 29 | ||
52 | void dccp_li_hist_delete(struct dccp_li_hist *hist) | 30 | static struct kmem_cache *dccp_li_cachep __read_mostly; |
53 | { | ||
54 | const char* name = kmem_cache_name(hist->dccplih_slab); | ||
55 | 31 | ||
56 | kmem_cache_destroy(hist->dccplih_slab); | 32 | static inline struct dccp_li_hist_entry *dccp_li_hist_entry_new(const gfp_t prio) |
57 | kfree(name); | 33 | { |
58 | kfree(hist); | 34 | return kmem_cache_alloc(dccp_li_cachep, prio); |
59 | } | 35 | } |
60 | 36 | ||
61 | EXPORT_SYMBOL_GPL(dccp_li_hist_delete); | 37 | static inline void dccp_li_hist_entry_delete(struct dccp_li_hist_entry *entry) |
38 | { | ||
39 | if (entry != NULL) | ||
40 | kmem_cache_free(dccp_li_cachep, entry); | ||
41 | } | ||
62 | 42 | ||
63 | void dccp_li_hist_purge(struct dccp_li_hist *hist, struct list_head *list) | 43 | void dccp_li_hist_purge(struct list_head *list) |
64 | { | 44 | { |
65 | struct dccp_li_hist_entry *entry, *next; | 45 | struct dccp_li_hist_entry *entry, *next; |
66 | 46 | ||
67 | list_for_each_entry_safe(entry, next, list, dccplih_node) { | 47 | list_for_each_entry_safe(entry, next, list, dccplih_node) { |
68 | list_del_init(&entry->dccplih_node); | 48 | list_del_init(&entry->dccplih_node); |
69 | kmem_cache_free(hist->dccplih_slab, entry); | 49 | kmem_cache_free(dccp_li_cachep, entry); |
70 | } | 50 | } |
71 | } | 51 | } |
72 | 52 | ||
@@ -118,16 +98,16 @@ u32 dccp_li_hist_calc_i_mean(struct list_head *list) | |||
118 | 98 | ||
119 | EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean); | 99 | EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean); |
120 | 100 | ||
121 | int dccp_li_hist_interval_new(struct dccp_li_hist *hist, | 101 | static int dccp_li_hist_interval_new(struct list_head *list, |
122 | struct list_head *list, const u64 seq_loss, const u8 win_loss) | 102 | const u64 seq_loss, const u8 win_loss) |
123 | { | 103 | { |
124 | struct dccp_li_hist_entry *entry; | 104 | struct dccp_li_hist_entry *entry; |
125 | int i; | 105 | int i; |
126 | 106 | ||
127 | for (i = 0; i < DCCP_LI_HIST_IVAL_F_LENGTH; i++) { | 107 | for (i = 0; i < DCCP_LI_HIST_IVAL_F_LENGTH; i++) { |
128 | entry = dccp_li_hist_entry_new(hist, GFP_ATOMIC); | 108 | entry = dccp_li_hist_entry_new(GFP_ATOMIC); |
129 | if (entry == NULL) { | 109 | if (entry == NULL) { |
130 | dccp_li_hist_purge(hist, list); | 110 | dccp_li_hist_purge(list); |
131 | DCCP_BUG("loss interval list entry is NULL"); | 111 | DCCP_BUG("loss interval list entry is NULL"); |
132 | return 0; | 112 | return 0; |
133 | } | 113 | } |
@@ -140,4 +120,176 @@ int dccp_li_hist_interval_new(struct dccp_li_hist *hist, | |||
140 | return 1; | 120 | return 1; |
141 | } | 121 | } |
142 | 122 | ||
143 | EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new); | 123 | /* calculate first loss interval |
124 | * | ||
125 | * returns estimated loss interval in usecs */ | ||
126 | static u32 dccp_li_calc_first_li(struct sock *sk, | ||
127 | struct list_head *hist_list, | ||
128 | struct timeval *last_feedback, | ||
129 | u16 s, u32 bytes_recv, | ||
130 | u32 previous_x_recv) | ||
131 | { | ||
132 | struct dccp_rx_hist_entry *entry, *next, *tail = NULL; | ||
133 | u32 x_recv, p; | ||
134 | suseconds_t rtt, delta; | ||
135 | struct timeval tstamp = { 0, 0 }; | ||
136 | int interval = 0; | ||
137 | int win_count = 0; | ||
138 | int step = 0; | ||
139 | u64 fval; | ||
140 | |||
141 | list_for_each_entry_safe(entry, next, hist_list, dccphrx_node) { | ||
142 | if (dccp_rx_hist_entry_data_packet(entry)) { | ||
143 | tail = entry; | ||
144 | |||
145 | switch (step) { | ||
146 | case 0: | ||
147 | tstamp = entry->dccphrx_tstamp; | ||
148 | win_count = entry->dccphrx_ccval; | ||
149 | step = 1; | ||
150 | break; | ||
151 | case 1: | ||
152 | interval = win_count - entry->dccphrx_ccval; | ||
153 | if (interval < 0) | ||
154 | interval += TFRC_WIN_COUNT_LIMIT; | ||
155 | if (interval > 4) | ||
156 | goto found; | ||
157 | break; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | if (unlikely(step == 0)) { | ||
163 | DCCP_WARN("%s(%p), packet history has no data packets!\n", | ||
164 | dccp_role(sk), sk); | ||
165 | return ~0; | ||
166 | } | ||
167 | |||
168 | if (unlikely(interval == 0)) { | ||
169 | DCCP_WARN("%s(%p), Could not find a win_count interval > 0." | ||
170 | "Defaulting to 1\n", dccp_role(sk), sk); | ||
171 | interval = 1; | ||
172 | } | ||
173 | found: | ||
174 | if (!tail) { | ||
175 | DCCP_CRIT("tail is null\n"); | ||
176 | return ~0; | ||
177 | } | ||
178 | |||
179 | delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp); | ||
180 | DCCP_BUG_ON(delta < 0); | ||
181 | |||
182 | rtt = delta * 4 / interval; | ||
183 | dccp_pr_debug("%s(%p), approximated RTT to %dus\n", | ||
184 | dccp_role(sk), sk, (int)rtt); | ||
185 | |||
186 | /* | ||
187 | * Determine the length of the first loss interval via inverse lookup. | ||
188 | * Assume that X_recv can be computed by the throughput equation | ||
189 | * s | ||
190 | * X_recv = -------- | ||
191 | * R * fval | ||
192 | * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1]. | ||
193 | */ | ||
194 | if (rtt == 0) { /* would result in divide-by-zero */ | ||
195 | DCCP_WARN("RTT==0\n"); | ||
196 | return ~0; | ||
197 | } | ||
198 | |||
199 | dccp_timestamp(sk, &tstamp); | ||
200 | delta = timeval_delta(&tstamp, last_feedback); | ||
201 | DCCP_BUG_ON(delta <= 0); | ||
202 | |||
203 | x_recv = scaled_div32(bytes_recv, delta); | ||
204 | if (x_recv == 0) { /* would also trigger divide-by-zero */ | ||
205 | DCCP_WARN("X_recv==0\n"); | ||
206 | if (previous_x_recv == 0) { | ||
207 | DCCP_BUG("stored value of X_recv is zero"); | ||
208 | return ~0; | ||
209 | } | ||
210 | x_recv = previous_x_recv; | ||
211 | } | ||
212 | |||
213 | fval = scaled_div(s, rtt); | ||
214 | fval = scaled_div32(fval, x_recv); | ||
215 | p = tfrc_calc_x_reverse_lookup(fval); | ||
216 | |||
217 | dccp_pr_debug("%s(%p), receive rate=%u bytes/s, implied " | ||
218 | "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); | ||
219 | |||
220 | if (p == 0) | ||
221 | return ~0; | ||
222 | else | ||
223 | return 1000000 / p; | ||
224 | } | ||
225 | |||
226 | void dccp_li_update_li(struct sock *sk, | ||
227 | struct list_head *li_hist_list, | ||
228 | struct list_head *hist_list, | ||
229 | struct timeval *last_feedback, u16 s, u32 bytes_recv, | ||
230 | u32 previous_x_recv, u64 seq_loss, u8 win_loss) | ||
231 | { | ||
232 | struct dccp_li_hist_entry *head; | ||
233 | u64 seq_temp; | ||
234 | |||
235 | if (list_empty(li_hist_list)) { | ||
236 | if (!dccp_li_hist_interval_new(li_hist_list, seq_loss, | ||
237 | win_loss)) | ||
238 | return; | ||
239 | |||
240 | head = list_entry(li_hist_list->next, struct dccp_li_hist_entry, | ||
241 | dccplih_node); | ||
242 | head->dccplih_interval = dccp_li_calc_first_li(sk, hist_list, | ||
243 | last_feedback, | ||
244 | s, bytes_recv, | ||
245 | previous_x_recv); | ||
246 | } else { | ||
247 | struct dccp_li_hist_entry *entry; | ||
248 | struct list_head *tail; | ||
249 | |||
250 | head = list_entry(li_hist_list->next, struct dccp_li_hist_entry, | ||
251 | dccplih_node); | ||
252 | /* FIXME win count check removed as was wrong */ | ||
253 | /* should make this check with receive history */ | ||
254 | /* and compare there as per section 10.2 of RFC4342 */ | ||
255 | |||
256 | /* new loss event detected */ | ||
257 | /* calculate last interval length */ | ||
258 | seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss); | ||
259 | entry = dccp_li_hist_entry_new(GFP_ATOMIC); | ||
260 | |||
261 | if (entry == NULL) { | ||
262 | DCCP_BUG("out of memory - can not allocate entry"); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | list_add(&entry->dccplih_node, li_hist_list); | ||
267 | |||
268 | tail = li_hist_list->prev; | ||
269 | list_del(tail); | ||
270 | kmem_cache_free(dccp_li_cachep, tail); | ||
271 | |||
272 | /* Create the newest interval */ | ||
273 | entry->dccplih_seqno = seq_loss; | ||
274 | entry->dccplih_interval = seq_temp; | ||
275 | entry->dccplih_win_count = win_loss; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | EXPORT_SYMBOL_GPL(dccp_li_update_li); | ||
280 | |||
281 | static __init int dccp_li_init(void) | ||
282 | { | ||
283 | dccp_li_cachep = kmem_cache_create("dccp_li_hist", | ||
284 | sizeof(struct dccp_li_hist_entry), | ||
285 | 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
286 | return dccp_li_cachep == NULL ? -ENOBUFS : 0; | ||
287 | } | ||
288 | |||
289 | static __exit void dccp_li_exit(void) | ||
290 | { | ||
291 | kmem_cache_destroy(dccp_li_cachep); | ||
292 | } | ||
293 | |||
294 | module_init(dccp_li_init); | ||
295 | module_exit(dccp_li_exit); | ||
diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h index eb257014dd74..906c806d6d9d 100644 --- a/net/dccp/ccids/lib/loss_interval.h +++ b/net/dccp/ccids/lib/loss_interval.h | |||
@@ -3,8 +3,8 @@ | |||
3 | /* | 3 | /* |
4 | * net/dccp/ccids/lib/loss_interval.h | 4 | * net/dccp/ccids/lib/loss_interval.h |
5 | * | 5 | * |
6 | * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. | 6 | * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. |
7 | * Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz> | 7 | * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> |
8 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 8 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
@@ -14,44 +14,16 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/list.h> | 16 | #include <linux/list.h> |
17 | #include <linux/slab.h> | ||
18 | #include <linux/time.h> | 17 | #include <linux/time.h> |
19 | 18 | ||
20 | #define DCCP_LI_HIST_IVAL_F_LENGTH 8 | 19 | extern void dccp_li_hist_purge(struct list_head *list); |
21 | |||
22 | struct dccp_li_hist { | ||
23 | struct kmem_cache *dccplih_slab; | ||
24 | }; | ||
25 | |||
26 | extern struct dccp_li_hist *dccp_li_hist_new(const char *name); | ||
27 | extern void dccp_li_hist_delete(struct dccp_li_hist *hist); | ||
28 | |||
29 | struct dccp_li_hist_entry { | ||
30 | struct list_head dccplih_node; | ||
31 | u64 dccplih_seqno:48, | ||
32 | dccplih_win_count:4; | ||
33 | u32 dccplih_interval; | ||
34 | }; | ||
35 | |||
36 | static inline struct dccp_li_hist_entry * | ||
37 | dccp_li_hist_entry_new(struct dccp_li_hist *hist, | ||
38 | const gfp_t prio) | ||
39 | { | ||
40 | return kmem_cache_alloc(hist->dccplih_slab, prio); | ||
41 | } | ||
42 | |||
43 | static inline void dccp_li_hist_entry_delete(struct dccp_li_hist *hist, | ||
44 | struct dccp_li_hist_entry *entry) | ||
45 | { | ||
46 | if (entry != NULL) | ||
47 | kmem_cache_free(hist->dccplih_slab, entry); | ||
48 | } | ||
49 | |||
50 | extern void dccp_li_hist_purge(struct dccp_li_hist *hist, | ||
51 | struct list_head *list); | ||
52 | 20 | ||
53 | extern u32 dccp_li_hist_calc_i_mean(struct list_head *list); | 21 | extern u32 dccp_li_hist_calc_i_mean(struct list_head *list); |
54 | 22 | ||
55 | extern int dccp_li_hist_interval_new(struct dccp_li_hist *hist, | 23 | extern void dccp_li_update_li(struct sock *sk, |
56 | struct list_head *list, const u64 seq_loss, const u8 win_loss); | 24 | struct list_head *li_hist_list, |
25 | struct list_head *hist_list, | ||
26 | struct timeval *last_feedback, u16 s, | ||
27 | u32 bytes_recv, u32 previous_x_recv, | ||
28 | u64 seq_loss, u8 win_loss); | ||
57 | #endif /* _DCCP_LI_HIST_ */ | 29 | #endif /* _DCCP_LI_HIST_ */ |