tcp_yeah.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. *
  3. * YeAH TCP
  4. *
  5. * For further details look at:
  6. * https://web.archive.org/web/20080316215752/http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf
  7. *
  8. */
  9. #include <linux/mm.h>
  10. #include <linux/module.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/inet_diag.h>
  13. #include <net/tcp.h>
  14. #include "tcp_vegas.h"
  15. #define TCP_YEAH_ALPHA 80 /* number of packets queued at the bottleneck */
  16. #define TCP_YEAH_GAMMA 1 /* fraction of queue to be removed per rtt */
  17. #define TCP_YEAH_DELTA 3 /* log minimum fraction of cwnd to be removed on loss */
  18. #define TCP_YEAH_EPSILON 1 /* log maximum fraction to be removed on early decongestion */
  19. #define TCP_YEAH_PHY 8 /* maximum delta from base */
  20. #define TCP_YEAH_RHO 16 /* minimum number of consecutive rtt to consider competition on loss */
  21. #define TCP_YEAH_ZETA 50 /* minimum number of state switches to reset reno_count */
  22. #define TCP_SCALABLE_AI_CNT 100U
  23. /* YeAH variables */
  24. struct yeah {
  25. struct vegas vegas; /* must be first */
  26. /* YeAH */
  27. u32 lastQ;
  28. u32 doing_reno_now;
  29. u32 reno_count;
  30. u32 fast_count;
  31. u32 pkts_acked;
  32. };
  33. static void tcp_yeah_init(struct sock *sk)
  34. {
  35. struct tcp_sock *tp = tcp_sk(sk);
  36. struct yeah *yeah = inet_csk_ca(sk);
  37. tcp_vegas_init(sk);
  38. yeah->doing_reno_now = 0;
  39. yeah->lastQ = 0;
  40. yeah->reno_count = 2;
  41. /* Ensure the MD arithmetic works. This is somewhat pedantic,
  42. * since I don't think we will see a cwnd this large. :) */
  43. tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
  44. }
  45. static void tcp_yeah_pkts_acked(struct sock *sk,
  46. const struct ack_sample *sample)
  47. {
  48. const struct inet_connection_sock *icsk = inet_csk(sk);
  49. struct yeah *yeah = inet_csk_ca(sk);
  50. if (icsk->icsk_ca_state == TCP_CA_Open)
  51. yeah->pkts_acked = sample->pkts_acked;
  52. tcp_vegas_pkts_acked(sk, sample);
  53. }
  54. static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
  55. {
  56. struct tcp_sock *tp = tcp_sk(sk);
  57. struct yeah *yeah = inet_csk_ca(sk);
  58. if (!tcp_is_cwnd_limited(sk))
  59. return;
  60. if (tcp_in_slow_start(tp))
  61. tcp_slow_start(tp, acked);
  62. else if (!yeah->doing_reno_now) {
  63. /* Scalable */
  64. tp->snd_cwnd_cnt += yeah->pkts_acked;
  65. if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)) {
  66. if (tp->snd_cwnd < tp->snd_cwnd_clamp)
  67. tp->snd_cwnd++;
  68. tp->snd_cwnd_cnt = 0;
  69. }
  70. yeah->pkts_acked = 1;
  71. } else {
  72. /* Reno */
  73. tcp_cong_avoid_ai(tp, tp->snd_cwnd, 1);
  74. }
  75. /* The key players are v_vegas.beg_snd_una and v_beg_snd_nxt.
  76. *
  77. * These are so named because they represent the approximate values
  78. * of snd_una and snd_nxt at the beginning of the current RTT. More
  79. * precisely, they represent the amount of data sent during the RTT.
  80. * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt,
  81. * we will calculate that (v_beg_snd_nxt - v_vegas.beg_snd_una) outstanding
  82. * bytes of data have been ACKed during the course of the RTT, giving
  83. * an "actual" rate of:
  84. *
  85. * (v_beg_snd_nxt - v_vegas.beg_snd_una) / (rtt duration)
  86. *
  87. * Unfortunately, v_vegas.beg_snd_una is not exactly equal to snd_una,
  88. * because delayed ACKs can cover more than one segment, so they
  89. * don't line up yeahly with the boundaries of RTTs.
  90. *
  91. * Another unfortunate fact of life is that delayed ACKs delay the
  92. * advance of the left edge of our send window, so that the number
  93. * of bytes we send in an RTT is often less than our cwnd will allow.
  94. * So we keep track of our cwnd separately, in v_beg_snd_cwnd.
  95. */
  96. if (after(ack, yeah->vegas.beg_snd_nxt)) {
  97. /* We do the Vegas calculations only if we got enough RTT
  98. * samples that we can be reasonably sure that we got
  99. * at least one RTT sample that wasn't from a delayed ACK.
  100. * If we only had 2 samples total,
  101. * then that means we're getting only 1 ACK per RTT, which
  102. * means they're almost certainly delayed ACKs.
  103. * If we have 3 samples, we should be OK.
  104. */
  105. if (yeah->vegas.cntRTT > 2) {
  106. u32 rtt, queue;
  107. u64 bw;
  108. /* We have enough RTT samples, so, using the Vegas
  109. * algorithm, we determine if we should increase or
  110. * decrease cwnd, and by how much.
  111. */
  112. /* Pluck out the RTT we are using for the Vegas
  113. * calculations. This is the min RTT seen during the
  114. * last RTT. Taking the min filters out the effects
  115. * of delayed ACKs, at the cost of noticing congestion
  116. * a bit later.
  117. */
  118. rtt = yeah->vegas.minRTT;
  119. /* Compute excess number of packets above bandwidth
  120. * Avoid doing full 64 bit divide.
  121. */
  122. bw = tp->snd_cwnd;
  123. bw *= rtt - yeah->vegas.baseRTT;
  124. do_div(bw, rtt);
  125. queue = bw;
  126. if (queue > TCP_YEAH_ALPHA ||
  127. rtt - yeah->vegas.baseRTT > (yeah->vegas.baseRTT / TCP_YEAH_PHY)) {
  128. if (queue > TCP_YEAH_ALPHA &&
  129. tp->snd_cwnd > yeah->reno_count) {
  130. u32 reduction = min(queue / TCP_YEAH_GAMMA ,
  131. tp->snd_cwnd >> TCP_YEAH_EPSILON);
  132. tp->snd_cwnd -= reduction;
  133. tp->snd_cwnd = max(tp->snd_cwnd,
  134. yeah->reno_count);
  135. tp->snd_ssthresh = tp->snd_cwnd;
  136. }
  137. if (yeah->reno_count <= 2)
  138. yeah->reno_count = max(tp->snd_cwnd>>1, 2U);
  139. else
  140. yeah->reno_count++;
  141. yeah->doing_reno_now = min(yeah->doing_reno_now + 1,
  142. 0xffffffU);
  143. } else {
  144. yeah->fast_count++;
  145. if (yeah->fast_count > TCP_YEAH_ZETA) {
  146. yeah->reno_count = 2;
  147. yeah->fast_count = 0;
  148. }
  149. yeah->doing_reno_now = 0;
  150. }
  151. yeah->lastQ = queue;
  152. }
  153. /* Save the extent of the current window so we can use this
  154. * at the end of the next RTT.
  155. */
  156. yeah->vegas.beg_snd_una = yeah->vegas.beg_snd_nxt;
  157. yeah->vegas.beg_snd_nxt = tp->snd_nxt;
  158. yeah->vegas.beg_snd_cwnd = tp->snd_cwnd;
  159. /* Wipe the slate clean for the next RTT. */
  160. yeah->vegas.cntRTT = 0;
  161. yeah->vegas.minRTT = 0x7fffffff;
  162. }
  163. }
  164. static u32 tcp_yeah_ssthresh(struct sock *sk)
  165. {
  166. const struct tcp_sock *tp = tcp_sk(sk);
  167. struct yeah *yeah = inet_csk_ca(sk);
  168. u32 reduction;
  169. if (yeah->doing_reno_now < TCP_YEAH_RHO) {
  170. reduction = yeah->lastQ;
  171. reduction = min(reduction, max(tp->snd_cwnd>>1, 2U));
  172. reduction = max(reduction, tp->snd_cwnd >> TCP_YEAH_DELTA);
  173. } else
  174. reduction = max(tp->snd_cwnd>>1, 2U);
  175. yeah->fast_count = 0;
  176. yeah->reno_count = max(yeah->reno_count>>1, 2U);
  177. return max_t(int, tp->snd_cwnd - reduction, 2);
  178. }
  179. static struct tcp_congestion_ops tcp_yeah __read_mostly = {
  180. .init = tcp_yeah_init,
  181. .ssthresh = tcp_yeah_ssthresh,
  182. .cong_avoid = tcp_yeah_cong_avoid,
  183. .set_state = tcp_vegas_state,
  184. .cwnd_event = tcp_vegas_cwnd_event,
  185. .get_info = tcp_vegas_get_info,
  186. .pkts_acked = tcp_yeah_pkts_acked,
  187. .owner = THIS_MODULE,
  188. .name = "yeah",
  189. };
  190. static int __init tcp_yeah_register(void)
  191. {
  192. BUG_ON(sizeof(struct yeah) > ICSK_CA_PRIV_SIZE);
  193. tcp_register_congestion_control(&tcp_yeah);
  194. return 0;
  195. }
  196. static void __exit tcp_yeah_unregister(void)
  197. {
  198. tcp_unregister_congestion_control(&tcp_yeah);
  199. }
  200. module_init(tcp_yeah_register);
  201. module_exit(tcp_yeah_unregister);
  202. MODULE_AUTHOR("Angelo P. Castellani");
  203. MODULE_LICENSE("GPL");
  204. MODULE_DESCRIPTION("YeAH TCP");