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/ccids/lib/loss_interval.c | |
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/ccids/lib/loss_interval.c')
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.c | 160 |
1 files changed, 160 insertions, 0 deletions
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); | ||