1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <linux/string.h>
37#include <linux/slab.h>
38#include "packet_history.h"
39#include "../../dccp.h"
40
41
42
43
44static struct kmem_cache *tfrc_tx_hist_slab;
45
46int __init tfrc_tx_packet_history_init(void)
47{
48 tfrc_tx_hist_slab = kmem_cache_create("tfrc_tx_hist",
49 sizeof(struct tfrc_tx_hist_entry),
50 0, SLAB_HWCACHE_ALIGN, NULL);
51 return tfrc_tx_hist_slab == NULL ? -ENOBUFS : 0;
52}
53
54void tfrc_tx_packet_history_exit(void)
55{
56 if (tfrc_tx_hist_slab != NULL) {
57 kmem_cache_destroy(tfrc_tx_hist_slab);
58 tfrc_tx_hist_slab = NULL;
59 }
60}
61
62int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno)
63{
64 struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist_slab, gfp_any());
65
66 if (entry == NULL)
67 return -ENOBUFS;
68 entry->seqno = seqno;
69 entry->stamp = ktime_get_real();
70 entry->next = *headp;
71 *headp = entry;
72 return 0;
73}
74
75void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp)
76{
77 struct tfrc_tx_hist_entry *head = *headp;
78
79 while (head != NULL) {
80 struct tfrc_tx_hist_entry *next = head->next;
81
82 kmem_cache_free(tfrc_tx_hist_slab, head);
83 head = next;
84 }
85
86 *headp = NULL;
87}
88
89
90
91
92static struct kmem_cache *tfrc_rx_hist_slab;
93
94int __init tfrc_rx_packet_history_init(void)
95{
96 tfrc_rx_hist_slab = kmem_cache_create("tfrc_rxh_cache",
97 sizeof(struct tfrc_rx_hist_entry),
98 0, SLAB_HWCACHE_ALIGN, NULL);
99 return tfrc_rx_hist_slab == NULL ? -ENOBUFS : 0;
100}
101
102void tfrc_rx_packet_history_exit(void)
103{
104 if (tfrc_rx_hist_slab != NULL) {
105 kmem_cache_destroy(tfrc_rx_hist_slab);
106 tfrc_rx_hist_slab = NULL;
107 }
108}
109
110static inline void tfrc_rx_hist_entry_from_skb(struct tfrc_rx_hist_entry *entry,
111 const struct sk_buff *skb,
112 const u64 ndp)
113{
114 const struct dccp_hdr *dh = dccp_hdr(skb);
115
116 entry->tfrchrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
117 entry->tfrchrx_ccval = dh->dccph_ccval;
118 entry->tfrchrx_type = dh->dccph_type;
119 entry->tfrchrx_ndp = ndp;
120 entry->tfrchrx_tstamp = ktime_get_real();
121}
122
123void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
124 const struct sk_buff *skb,
125 const u64 ndp)
126{
127 struct tfrc_rx_hist_entry *entry = tfrc_rx_hist_last_rcv(h);
128
129 tfrc_rx_hist_entry_from_skb(entry, skb, ndp);
130}
131
132
133int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb)
134{
135 const u64 seq = DCCP_SKB_CB(skb)->dccpd_seq;
136 int i;
137
138 if (dccp_delta_seqno(tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, seq) <= 0)
139 return 1;
140
141 for (i = 1; i <= h->loss_count; i++)
142 if (tfrc_rx_hist_entry(h, i)->tfrchrx_seqno == seq)
143 return 1;
144
145 return 0;
146}
147
148static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b)
149{
150 const u8 idx_a = tfrc_rx_hist_index(h, a),
151 idx_b = tfrc_rx_hist_index(h, b);
152
153 swap(h->ring[idx_a], h->ring[idx_b]);
154}
155
156
157
158
159
160
161
162
163
164
165static void __do_track_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u64 n1)
166{
167 u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
168 s1 = DCCP_SKB_CB(skb)->dccpd_seq;
169
170 if (!dccp_loss_free(s0, s1, n1)) {
171 h->loss_count = 1;
172 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n1);
173 }
174}
175
176static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2)
177{
178 u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
179 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
180 s2 = DCCP_SKB_CB(skb)->dccpd_seq;
181
182 if (likely(dccp_delta_seqno(s1, s2) > 0)) {
183 h->loss_count = 2;
184 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n2);
185 return;
186 }
187
188
189
190 if (dccp_loss_free(s0, s2, n2)) {
191 u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp;
192
193 if (dccp_loss_free(s2, s1, n1)) {
194
195 h->loss_count = 0;
196 h->loss_start = tfrc_rx_hist_index(h, 1);
197 } else
198
199 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2);
200
201 } else {
202
203
204
205 tfrc_rx_hist_swap(h, 0, 3);
206 h->loss_start = tfrc_rx_hist_index(h, 3);
207 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n2);
208 h->loss_count = 2;
209 }
210}
211
212
213static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3)
214{
215 u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
216 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
217 s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno,
218 s3 = DCCP_SKB_CB(skb)->dccpd_seq;
219
220 if (likely(dccp_delta_seqno(s2, s3) > 0)) {
221 h->loss_count = 3;
222 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 3), skb, n3);
223 return 1;
224 }
225
226
227
228 if (dccp_delta_seqno(s1, s3) > 0) {
229
230
231
232 tfrc_rx_hist_swap(h, 2, 3);
233 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n3);
234 h->loss_count = 3;
235 return 1;
236 }
237
238
239
240 if (dccp_loss_free(s0, s3, n3)) {
241 u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp;
242
243 if (dccp_loss_free(s3, s1, n1)) {
244
245 u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp;
246
247 if (dccp_loss_free(s1, s2, n2)) {
248
249 h->loss_start = tfrc_rx_hist_index(h, 2);
250 h->loss_count = 0;
251 } else {
252
253 h->loss_start = tfrc_rx_hist_index(h, 1);
254 h->loss_count = 1;
255 }
256
257 } else
258 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n3);
259
260 return 0;
261 }
262
263
264
265
266
267 tfrc_rx_hist_swap(h, 0, 3);
268 h->loss_start = tfrc_rx_hist_index(h, 3);
269 tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n3);
270 h->loss_count = 3;
271
272 return 1;
273}
274
275
276static void __three_after_loss(struct tfrc_rx_hist *h)
277{
278
279
280
281
282
283
284 u64 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
285 s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno,
286 s3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_seqno;
287 u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp,
288 n3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_ndp;
289
290 if (dccp_loss_free(s1, s2, n2)) {
291
292 if (dccp_loss_free(s2, s3, n3)) {
293
294 h->loss_start = tfrc_rx_hist_index(h, 3);
295 h->loss_count = 0;
296 } else {
297
298 h->loss_start = tfrc_rx_hist_index(h, 2);
299 h->loss_count = 1;
300 }
301
302 } else {
303 h->loss_start = tfrc_rx_hist_index(h, 1);
304 h->loss_count = 2;
305 }
306}
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324int tfrc_rx_handle_loss(struct tfrc_rx_hist *h,
325 struct tfrc_loss_hist *lh,
326 struct sk_buff *skb, const u64 ndp,
327 u32 (*calc_first_li)(struct sock *), struct sock *sk)
328{
329 int is_new_loss = 0;
330
331 if (h->loss_count == 0) {
332 __do_track_loss(h, skb, ndp);
333 } else if (h->loss_count == 1) {
334 __one_after_loss(h, skb, ndp);
335 } else if (h->loss_count != 2) {
336 DCCP_BUG("invalid loss_count %d", h->loss_count);
337 } else if (__two_after_loss(h, skb, ndp)) {
338
339
340
341 is_new_loss = tfrc_lh_interval_add(lh, h, calc_first_li, sk);
342 __three_after_loss(h);
343 }
344 return is_new_loss;
345}
346
347int tfrc_rx_hist_alloc(struct tfrc_rx_hist *h)
348{
349 int i;
350
351 for (i = 0; i <= TFRC_NDUPACK; i++) {
352 h->ring[i] = kmem_cache_alloc(tfrc_rx_hist_slab, GFP_ATOMIC);
353 if (h->ring[i] == NULL)
354 goto out_free;
355 }
356
357 h->loss_count = h->loss_start = 0;
358 return 0;
359
360out_free:
361 while (i-- != 0) {
362 kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
363 h->ring[i] = NULL;
364 }
365 return -ENOBUFS;
366}
367
368void tfrc_rx_hist_purge(struct tfrc_rx_hist *h)
369{
370 int i;
371
372 for (i = 0; i <= TFRC_NDUPACK; ++i)
373 if (h->ring[i] != NULL) {
374 kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
375 h->ring[i] = NULL;
376 }
377}
378
379
380
381
382static inline struct tfrc_rx_hist_entry *
383 tfrc_rx_hist_rtt_last_s(const struct tfrc_rx_hist *h)
384{
385 return h->ring[0];
386}
387
388
389
390
391static inline struct tfrc_rx_hist_entry *
392 tfrc_rx_hist_rtt_prev_s(const struct tfrc_rx_hist *h)
393{
394 return h->ring[h->rtt_sample_prev];
395}
396
397
398
399
400
401
402u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb)
403{
404 u32 sample = 0,
405 delta_v = SUB16(dccp_hdr(skb)->dccph_ccval,
406 tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
407
408 if (delta_v < 1 || delta_v > 4) {
409 if (h->rtt_sample_prev == 2) {
410 sample = SUB16(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
411 tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
412 if (sample)
413 sample = 4 / sample *
414 ktime_us_delta(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_tstamp,
415 tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp);
416 else
417
418
419
420
421
422 DCCP_BUG("please report to dccp@vger.kernel.org"
423 " => prev = %u, last = %u",
424 tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
425 tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
426 } else if (delta_v < 1) {
427 h->rtt_sample_prev = 1;
428 goto keep_ref_for_next_time;
429 }
430
431 } else if (delta_v == 4)
432 sample = ktime_to_us(net_timedelta(tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp));
433 else {
434 h->rtt_sample_prev = 2;
435 goto keep_ref_for_next_time;
436 }
437
438 if (unlikely(sample > DCCP_SANE_RTT_MAX)) {
439 DCCP_WARN("RTT sample %u too large, using max\n", sample);
440 sample = DCCP_SANE_RTT_MAX;
441 }
442
443 h->rtt_sample_prev = 0;
444keep_ref_for_next_time:
445
446 return sample;
447}
448