diff options
| author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2007-06-14 16:41:28 -0400 |
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:15:20 -0400 |
| commit | cc0a910b942d11069d35f52b2c0ed0e229e2fb46 (patch) | |
| tree | 9d378b79a25b7c5f03ce9f713f00648781953dbd /net/dccp | |
| parent | 878ac60023c4ba11a7fbf0b1dfe07b8472c0d6ce (diff) | |
[DCCP] loss_interval: Move ccid3_hc_rx_update_li to loss_interval
Renaming it to dccp_li_update_li.
Also based on previous work by Ian McDonald.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
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_ */ |
