aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ccids
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ccids')
-rw-r--r--net/dccp/ccids/ccid3.c212
-rw-r--r--net/dccp/ccids/ccid3.h5
-rw-r--r--net/dccp/ccids/lib/loss_interval.c246
-rw-r--r--net/dccp/ccids/lib/loss_interval.h46
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
50static struct dccp_tx_hist *ccid3_tx_hist; 50static struct dccp_tx_hist *ccid3_tx_hist;
51static struct dccp_rx_hist *ccid3_rx_hist; 51static struct dccp_rx_hist *ccid3_rx_hist;
52static 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 */
196static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx, 195static 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
826static 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 }
871found:
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
923static 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
970static int ccid3_hc_rx_detect_loss(struct sock *sk, 814static 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
1158static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) 1009static 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;
1246out: 1093out:
1247 return rc; 1094 return rc;
1248 1095
1249out_free_loss_interval_history:
1250 dccp_li_hist_delete(ccid3_li_hist);
1251 ccid3_li_hist = NULL;
1252out_free_tx: 1096out_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}
1279module_exit(ccid3_module_exit); 1119module_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
19struct 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;
40out:
41 return hist;
42out_free_slab_name:
43 kfree(slab_name);
44out_free_hist:
45 kfree(hist);
46 hist = NULL;
47 goto out;
48}
49 22
50EXPORT_SYMBOL_GPL(dccp_li_hist_new); 23struct 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
52void dccp_li_hist_delete(struct dccp_li_hist *hist) 30static 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); 32static 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
61EXPORT_SYMBOL_GPL(dccp_li_hist_delete); 37static 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
63void dccp_li_hist_purge(struct dccp_li_hist *hist, struct list_head *list) 43void 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
119EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean); 99EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean);
120 100
121int dccp_li_hist_interval_new(struct dccp_li_hist *hist, 101static 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
143EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new); 123/* calculate first loss interval
124 *
125 * returns estimated loss interval in usecs */
126static 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 }
173found:
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
226void 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
279EXPORT_SYMBOL_GPL(dccp_li_update_li);
280
281static __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
289static __exit void dccp_li_exit(void)
290{
291 kmem_cache_destroy(dccp_li_cachep);
292}
293
294module_init(dccp_li_init);
295module_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 19extern void dccp_li_hist_purge(struct list_head *list);
21
22struct dccp_li_hist {
23 struct kmem_cache *dccplih_slab;
24};
25
26extern struct dccp_li_hist *dccp_li_hist_new(const char *name);
27extern void dccp_li_hist_delete(struct dccp_li_hist *hist);
28
29struct 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
36static 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
43static 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
50extern void dccp_li_hist_purge(struct dccp_li_hist *hist,
51 struct list_head *list);
52 20
53extern u32 dccp_li_hist_calc_i_mean(struct list_head *list); 21extern u32 dccp_li_hist_calc_i_mean(struct list_head *list);
54 22
55extern int dccp_li_hist_interval_new(struct dccp_li_hist *hist, 23extern 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_ */