/kern_oII/net/dccp/ccids/lib/packet_history.c

http://omnia2droid.googlecode.com/ · C · 489 lines · 296 code · 70 blank · 123 comment · 67 complexity · 33389fb7d03e1e081eb7a57cc24df6bb MD5 · raw file

  1. /*
  2. * net/dccp/packet_history.c
  3. *
  4. * Copyright (c) 2007 The University of Aberdeen, Scotland, UK
  5. * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
  6. *
  7. * An implementation of the DCCP protocol
  8. *
  9. * This code has been developed by the University of Waikato WAND
  10. * research group. For further information please see http://www.wand.net.nz/
  11. * or e-mail Ian McDonald - ian.mcdonald@jandi.co.nz
  12. *
  13. * This code also uses code from Lulea University, rereleased as GPL by its
  14. * authors:
  15. * Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
  16. *
  17. * Changes to meet Linux coding standards, to make it meet latest ccid3 draft
  18. * and to make it work as a loadable module in the DCCP stack written by
  19. * Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
  20. *
  21. * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  22. *
  23. * This program is free software; you can redistribute it and/or modify
  24. * it under the terms of the GNU General Public License as published by
  25. * the Free Software Foundation; either version 2 of the License, or
  26. * (at your option) any later version.
  27. *
  28. * This program is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. * GNU General Public License for more details.
  32. *
  33. * You should have received a copy of the GNU General Public License
  34. * along with this program; if not, write to the Free Software
  35. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  36. */
  37. #include <linux/string.h>
  38. #include <linux/slab.h>
  39. #include "packet_history.h"
  40. #include "../../dccp.h"
  41. /**
  42. * tfrc_tx_hist_entry - Simple singly-linked TX history list
  43. * @next: next oldest entry (LIFO order)
  44. * @seqno: sequence number of this entry
  45. * @stamp: send time of packet with sequence number @seqno
  46. */
  47. struct tfrc_tx_hist_entry {
  48. struct tfrc_tx_hist_entry *next;
  49. u64 seqno;
  50. ktime_t stamp;
  51. };
  52. /*
  53. * Transmitter History Routines
  54. */
  55. static struct kmem_cache *tfrc_tx_hist_slab;
  56. int __init tfrc_tx_packet_history_init(void)
  57. {
  58. tfrc_tx_hist_slab = kmem_cache_create("tfrc_tx_hist",
  59. sizeof(struct tfrc_tx_hist_entry),
  60. 0, SLAB_HWCACHE_ALIGN, NULL);
  61. return tfrc_tx_hist_slab == NULL ? -ENOBUFS : 0;
  62. }
  63. void tfrc_tx_packet_history_exit(void)
  64. {
  65. if (tfrc_tx_hist_slab != NULL) {
  66. kmem_cache_destroy(tfrc_tx_hist_slab);
  67. tfrc_tx_hist_slab = NULL;
  68. }
  69. }
  70. static struct tfrc_tx_hist_entry *
  71. tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno)
  72. {
  73. while (head != NULL && head->seqno != seqno)
  74. head = head->next;
  75. return head;
  76. }
  77. int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno)
  78. {
  79. struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist_slab, gfp_any());
  80. if (entry == NULL)
  81. return -ENOBUFS;
  82. entry->seqno = seqno;
  83. entry->stamp = ktime_get_real();
  84. entry->next = *headp;
  85. *headp = entry;
  86. return 0;
  87. }
  88. void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp)
  89. {
  90. struct tfrc_tx_hist_entry *head = *headp;
  91. while (head != NULL) {
  92. struct tfrc_tx_hist_entry *next = head->next;
  93. kmem_cache_free(tfrc_tx_hist_slab, head);
  94. head = next;
  95. }
  96. *headp = NULL;
  97. }
  98. u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, const u64 seqno,
  99. const ktime_t now)
  100. {
  101. u32 rtt = 0;
  102. struct tfrc_tx_hist_entry *packet = tfrc_tx_hist_find_entry(head, seqno);
  103. if (packet != NULL) {
  104. rtt = ktime_us_delta(now, packet->stamp);
  105. /*
  106. * Garbage-collect older (irrelevant) entries:
  107. */
  108. tfrc_tx_hist_purge(&packet->next);
  109. }
  110. return rtt;
  111. }
  112. /*
  113. * Receiver History Routines
  114. */
  115. static struct kmem_cache *tfrc_rx_hist_slab;
  116. int __init tfrc_rx_packet_history_init(void)
  117. {
  118. tfrc_rx_hist_slab = kmem_cache_create("tfrc_rxh_cache",
  119. sizeof(struct tfrc_rx_hist_entry),
  120. 0, SLAB_HWCACHE_ALIGN, NULL);
  121. return tfrc_rx_hist_slab == NULL ? -ENOBUFS : 0;
  122. }
  123. void tfrc_rx_packet_history_exit(void)
  124. {
  125. if (tfrc_rx_hist_slab != NULL) {
  126. kmem_cache_destroy(tfrc_rx_hist_slab);
  127. tfrc_rx_hist_slab = NULL;
  128. }
  129. }
  130. static inline void tfrc_rx_hist_entry_from_skb(struct tfrc_rx_hist_entry *entry,
  131. const struct sk_buff *skb,
  132. const u64 ndp)
  133. {
  134. const struct dccp_hdr *dh = dccp_hdr(skb);
  135. entry->tfrchrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
  136. entry->tfrchrx_ccval = dh->dccph_ccval;
  137. entry->tfrchrx_type = dh->dccph_type;
  138. entry->tfrchrx_ndp = ndp;
  139. entry->tfrchrx_tstamp = ktime_get_real();
  140. }
  141. void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
  142. const struct sk_buff *skb,
  143. const u64 ndp)
  144. {
  145. struct tfrc_rx_hist_entry *entry = tfrc_rx_hist_last_rcv(h);
  146. tfrc_rx_hist_entry_from_skb(entry, skb, ndp);
  147. }
  148. /* has the packet contained in skb been seen before? */
  149. int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb)
  150. {
  151. const u64 seq = DCCP_SKB_CB(skb)->dccpd_seq;
  152. int i;
  153. if (dccp_delta_seqno(tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, seq) <= 0)
  154. return 1;
  155. for (i = 1; i <= h->loss_count; i++)
  156. if (tfrc_rx_hist_entry(h, i)->tfrchrx_seqno == seq)
  157. return 1;
  158. return 0;
  159. }
  160. static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b)
  161. {
  162. const u8 idx_a = tfrc_rx_hist_index(h, a),
  163. idx_b = tfrc_rx_hist_index(h, b);
  164. struct tfrc_rx_hist_entry *tmp = h->ring[idx_a];
  165. h->ring[idx_a] = h->ring[idx_b];
  166. h->ring[idx_b] = tmp;
  167. }
  168. /*
  169. * Private helper functions for loss detection.
  170. *
  171. * In the descriptions, `Si' refers to the sequence number of entry number i,
  172. * whose NDP count is `Ni' (lower case is used for variables).
  173. * Note: All __xxx_loss functions expect that a test against duplicates has been
  174. * performed already: the seqno of the skb must not be less than the seqno
  175. * of loss_prev; and it must not equal that of any valid history entry.
  176. */
  177. static void __do_track_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u64 n1)
  178. {
  179. u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
  180. s1 = DCCP_SKB_CB(skb)->dccpd_seq;
  181. if (!dccp_loss_free(s0, s1, n1)) { /* gap between S0 and S1 */
  182. h->loss_count = 1;
  183. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n1);
  184. }
  185. }
  186. static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2)
  187. {
  188. u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
  189. s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
  190. s2 = DCCP_SKB_CB(skb)->dccpd_seq;
  191. if (likely(dccp_delta_seqno(s1, s2) > 0)) { /* S1 < S2 */
  192. h->loss_count = 2;
  193. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n2);
  194. return;
  195. }
  196. /* S0 < S2 < S1 */
  197. if (dccp_loss_free(s0, s2, n2)) {
  198. u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp;
  199. if (dccp_loss_free(s2, s1, n1)) {
  200. /* hole is filled: S0, S2, and S1 are consecutive */
  201. h->loss_count = 0;
  202. h->loss_start = tfrc_rx_hist_index(h, 1);
  203. } else
  204. /* gap between S2 and S1: just update loss_prev */
  205. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2);
  206. } else { /* gap between S0 and S2 */
  207. /*
  208. * Reorder history to insert S2 between S0 and S1
  209. */
  210. tfrc_rx_hist_swap(h, 0, 3);
  211. h->loss_start = tfrc_rx_hist_index(h, 3);
  212. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n2);
  213. h->loss_count = 2;
  214. }
  215. }
  216. /* return 1 if a new loss event has been identified */
  217. static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3)
  218. {
  219. u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
  220. s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
  221. s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno,
  222. s3 = DCCP_SKB_CB(skb)->dccpd_seq;
  223. if (likely(dccp_delta_seqno(s2, s3) > 0)) { /* S2 < S3 */
  224. h->loss_count = 3;
  225. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 3), skb, n3);
  226. return 1;
  227. }
  228. /* S3 < S2 */
  229. if (dccp_delta_seqno(s1, s3) > 0) { /* S1 < S3 < S2 */
  230. /*
  231. * Reorder history to insert S3 between S1 and S2
  232. */
  233. tfrc_rx_hist_swap(h, 2, 3);
  234. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n3);
  235. h->loss_count = 3;
  236. return 1;
  237. }
  238. /* S0 < S3 < S1 */
  239. if (dccp_loss_free(s0, s3, n3)) {
  240. u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp;
  241. if (dccp_loss_free(s3, s1, n1)) {
  242. /* hole between S0 and S1 filled by S3 */
  243. u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp;
  244. if (dccp_loss_free(s1, s2, n2)) {
  245. /* entire hole filled by S0, S3, S1, S2 */
  246. h->loss_start = tfrc_rx_hist_index(h, 2);
  247. h->loss_count = 0;
  248. } else {
  249. /* gap remains between S1 and S2 */
  250. h->loss_start = tfrc_rx_hist_index(h, 1);
  251. h->loss_count = 1;
  252. }
  253. } else /* gap exists between S3 and S1, loss_count stays at 2 */
  254. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n3);
  255. return 0;
  256. }
  257. /*
  258. * The remaining case: S0 < S3 < S1 < S2; gap between S0 and S3
  259. * Reorder history to insert S3 between S0 and S1.
  260. */
  261. tfrc_rx_hist_swap(h, 0, 3);
  262. h->loss_start = tfrc_rx_hist_index(h, 3);
  263. tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n3);
  264. h->loss_count = 3;
  265. return 1;
  266. }
  267. /* recycle RX history records to continue loss detection if necessary */
  268. static void __three_after_loss(struct tfrc_rx_hist *h)
  269. {
  270. /*
  271. * At this stage we know already that there is a gap between S0 and S1
  272. * (since S0 was the highest sequence number received before detecting
  273. * the loss). To recycle the loss record, it is thus only necessary to
  274. * check for other possible gaps between S1/S2 and between S2/S3.
  275. */
  276. u64 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
  277. s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno,
  278. s3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_seqno;
  279. u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp,
  280. n3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_ndp;
  281. if (dccp_loss_free(s1, s2, n2)) {
  282. if (dccp_loss_free(s2, s3, n3)) {
  283. /* no gap between S2 and S3: entire hole is filled */
  284. h->loss_start = tfrc_rx_hist_index(h, 3);
  285. h->loss_count = 0;
  286. } else {
  287. /* gap between S2 and S3 */
  288. h->loss_start = tfrc_rx_hist_index(h, 2);
  289. h->loss_count = 1;
  290. }
  291. } else { /* gap between S1 and S2 */
  292. h->loss_start = tfrc_rx_hist_index(h, 1);
  293. h->loss_count = 2;
  294. }
  295. }
  296. /**
  297. * tfrc_rx_handle_loss - Loss detection and further processing
  298. * @h: The non-empty RX history object
  299. * @lh: Loss Intervals database to update
  300. * @skb: Currently received packet
  301. * @ndp: The NDP count belonging to @skb
  302. * @calc_first_li: Caller-dependent computation of first loss interval in @lh
  303. * @sk: Used by @calc_first_li (see tfrc_lh_interval_add)
  304. * Chooses action according to pending loss, updates LI database when a new
  305. * loss was detected, and does required post-processing. Returns 1 when caller
  306. * should send feedback, 0 otherwise.
  307. * Since it also takes care of reordering during loss detection and updates the
  308. * records accordingly, the caller should not perform any more RX history
  309. * operations when loss_count is greater than 0 after calling this function.
  310. */
  311. int tfrc_rx_handle_loss(struct tfrc_rx_hist *h,
  312. struct tfrc_loss_hist *lh,
  313. struct sk_buff *skb, const u64 ndp,
  314. u32 (*calc_first_li)(struct sock *), struct sock *sk)
  315. {
  316. int is_new_loss = 0;
  317. if (h->loss_count == 0) {
  318. __do_track_loss(h, skb, ndp);
  319. } else if (h->loss_count == 1) {
  320. __one_after_loss(h, skb, ndp);
  321. } else if (h->loss_count != 2) {
  322. DCCP_BUG("invalid loss_count %d", h->loss_count);
  323. } else if (__two_after_loss(h, skb, ndp)) {
  324. /*
  325. * Update Loss Interval database and recycle RX records
  326. */
  327. is_new_loss = tfrc_lh_interval_add(lh, h, calc_first_li, sk);
  328. __three_after_loss(h);
  329. }
  330. return is_new_loss;
  331. }
  332. int tfrc_rx_hist_alloc(struct tfrc_rx_hist *h)
  333. {
  334. int i;
  335. for (i = 0; i <= TFRC_NDUPACK; i++) {
  336. h->ring[i] = kmem_cache_alloc(tfrc_rx_hist_slab, GFP_ATOMIC);
  337. if (h->ring[i] == NULL)
  338. goto out_free;
  339. }
  340. h->loss_count = h->loss_start = 0;
  341. return 0;
  342. out_free:
  343. while (i-- != 0) {
  344. kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
  345. h->ring[i] = NULL;
  346. }
  347. return -ENOBUFS;
  348. }
  349. void tfrc_rx_hist_purge(struct tfrc_rx_hist *h)
  350. {
  351. int i;
  352. for (i = 0; i <= TFRC_NDUPACK; ++i)
  353. if (h->ring[i] != NULL) {
  354. kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
  355. h->ring[i] = NULL;
  356. }
  357. }
  358. /**
  359. * tfrc_rx_hist_rtt_last_s - reference entry to compute RTT samples against
  360. */
  361. static inline struct tfrc_rx_hist_entry *
  362. tfrc_rx_hist_rtt_last_s(const struct tfrc_rx_hist *h)
  363. {
  364. return h->ring[0];
  365. }
  366. /**
  367. * tfrc_rx_hist_rtt_prev_s: previously suitable (wrt rtt_last_s) RTT-sampling entry
  368. */
  369. static inline struct tfrc_rx_hist_entry *
  370. tfrc_rx_hist_rtt_prev_s(const struct tfrc_rx_hist *h)
  371. {
  372. return h->ring[h->rtt_sample_prev];
  373. }
  374. /**
  375. * tfrc_rx_hist_sample_rtt - Sample RTT from timestamp / CCVal
  376. * Based on ideas presented in RFC 4342, 8.1. Returns 0 if it was not able
  377. * to compute a sample with given data - calling function should check this.
  378. */
  379. u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb)
  380. {
  381. u32 sample = 0,
  382. delta_v = SUB16(dccp_hdr(skb)->dccph_ccval,
  383. tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
  384. if (delta_v < 1 || delta_v > 4) { /* unsuitable CCVal delta */
  385. if (h->rtt_sample_prev == 2) { /* previous candidate stored */
  386. sample = SUB16(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
  387. tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
  388. if (sample)
  389. sample = 4 / sample *
  390. ktime_us_delta(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_tstamp,
  391. tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp);
  392. else /*
  393. * FIXME: This condition is in principle not
  394. * possible but occurs when CCID is used for
  395. * two-way data traffic. I have tried to trace
  396. * it, but the cause does not seem to be here.
  397. */
  398. DCCP_BUG("please report to dccp@vger.kernel.org"
  399. " => prev = %u, last = %u",
  400. tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
  401. tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
  402. } else if (delta_v < 1) {
  403. h->rtt_sample_prev = 1;
  404. goto keep_ref_for_next_time;
  405. }
  406. } else if (delta_v == 4) /* optimal match */
  407. sample = ktime_to_us(net_timedelta(tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp));
  408. else { /* suboptimal match */
  409. h->rtt_sample_prev = 2;
  410. goto keep_ref_for_next_time;
  411. }
  412. if (unlikely(sample > DCCP_SANE_RTT_MAX)) {
  413. DCCP_WARN("RTT sample %u too large, using max\n", sample);
  414. sample = DCCP_SANE_RTT_MAX;
  415. }
  416. h->rtt_sample_prev = 0; /* use current entry as next reference */
  417. keep_ref_for_next_time:
  418. return sample;
  419. }