tcp_metrics.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include <linux/module.h>
  2. #include <linux/cache.h>
  3. #include <linux/tcp.h>
  4. #include <net/inet_connection_sock.h>
  5. #include <net/request_sock.h>
  6. #include <net/sock.h>
  7. #include <net/dst.h>
  8. #include <net/tcp.h>
  9. int sysctl_tcp_nometrics_save __read_mostly;
  10. /* Save metrics learned by this TCP session. This function is called
  11. * only, when TCP finishes successfully i.e. when it enters TIME-WAIT
  12. * or goes from LAST-ACK to CLOSE.
  13. */
  14. void tcp_update_metrics(struct sock *sk)
  15. {
  16. struct tcp_sock *tp = tcp_sk(sk);
  17. struct dst_entry *dst = __sk_dst_get(sk);
  18. if (sysctl_tcp_nometrics_save)
  19. return;
  20. if (dst && (dst->flags & DST_HOST)) {
  21. const struct inet_connection_sock *icsk = inet_csk(sk);
  22. int m;
  23. unsigned long rtt;
  24. dst_confirm(dst);
  25. if (icsk->icsk_backoff || !tp->srtt) {
  26. /* This session failed to estimate rtt. Why?
  27. * Probably, no packets returned in time.
  28. * Reset our results.
  29. */
  30. if (!(dst_metric_locked(dst, RTAX_RTT)))
  31. dst_metric_set(dst, RTAX_RTT, 0);
  32. return;
  33. }
  34. rtt = dst_metric_rtt(dst, RTAX_RTT);
  35. m = rtt - tp->srtt;
  36. /* If newly calculated rtt larger than stored one,
  37. * store new one. Otherwise, use EWMA. Remember,
  38. * rtt overestimation is always better than underestimation.
  39. */
  40. if (!(dst_metric_locked(dst, RTAX_RTT))) {
  41. if (m <= 0)
  42. set_dst_metric_rtt(dst, RTAX_RTT, tp->srtt);
  43. else
  44. set_dst_metric_rtt(dst, RTAX_RTT, rtt - (m >> 3));
  45. }
  46. if (!(dst_metric_locked(dst, RTAX_RTTVAR))) {
  47. unsigned long var;
  48. if (m < 0)
  49. m = -m;
  50. /* Scale deviation to rttvar fixed point */
  51. m >>= 1;
  52. if (m < tp->mdev)
  53. m = tp->mdev;
  54. var = dst_metric_rtt(dst, RTAX_RTTVAR);
  55. if (m >= var)
  56. var = m;
  57. else
  58. var -= (var - m) >> 2;
  59. set_dst_metric_rtt(dst, RTAX_RTTVAR, var);
  60. }
  61. if (tcp_in_initial_slowstart(tp)) {
  62. /* Slow start still did not finish. */
  63. if (dst_metric(dst, RTAX_SSTHRESH) &&
  64. !dst_metric_locked(dst, RTAX_SSTHRESH) &&
  65. (tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH))
  66. dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_cwnd >> 1);
  67. if (!dst_metric_locked(dst, RTAX_CWND) &&
  68. tp->snd_cwnd > dst_metric(dst, RTAX_CWND))
  69. dst_metric_set(dst, RTAX_CWND, tp->snd_cwnd);
  70. } else if (tp->snd_cwnd > tp->snd_ssthresh &&
  71. icsk->icsk_ca_state == TCP_CA_Open) {
  72. /* Cong. avoidance phase, cwnd is reliable. */
  73. if (!dst_metric_locked(dst, RTAX_SSTHRESH))
  74. dst_metric_set(dst, RTAX_SSTHRESH,
  75. max(tp->snd_cwnd >> 1, tp->snd_ssthresh));
  76. if (!dst_metric_locked(dst, RTAX_CWND))
  77. dst_metric_set(dst, RTAX_CWND,
  78. (dst_metric(dst, RTAX_CWND) +
  79. tp->snd_cwnd) >> 1);
  80. } else {
  81. /* Else slow start did not finish, cwnd is non-sense,
  82. ssthresh may be also invalid.
  83. */
  84. if (!dst_metric_locked(dst, RTAX_CWND))
  85. dst_metric_set(dst, RTAX_CWND,
  86. (dst_metric(dst, RTAX_CWND) +
  87. tp->snd_ssthresh) >> 1);
  88. if (dst_metric(dst, RTAX_SSTHRESH) &&
  89. !dst_metric_locked(dst, RTAX_SSTHRESH) &&
  90. tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH))
  91. dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_ssthresh);
  92. }
  93. if (!dst_metric_locked(dst, RTAX_REORDERING)) {
  94. if (dst_metric(dst, RTAX_REORDERING) < tp->reordering &&
  95. tp->reordering != sysctl_tcp_reordering)
  96. dst_metric_set(dst, RTAX_REORDERING, tp->reordering);
  97. }
  98. }
  99. }
  100. /* Initialize metrics on socket. */
  101. void tcp_init_metrics(struct sock *sk)
  102. {
  103. struct tcp_sock *tp = tcp_sk(sk);
  104. struct dst_entry *dst = __sk_dst_get(sk);
  105. if (dst == NULL)
  106. goto reset;
  107. dst_confirm(dst);
  108. if (dst_metric_locked(dst, RTAX_CWND))
  109. tp->snd_cwnd_clamp = dst_metric(dst, RTAX_CWND);
  110. if (dst_metric(dst, RTAX_SSTHRESH)) {
  111. tp->snd_ssthresh = dst_metric(dst, RTAX_SSTHRESH);
  112. if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
  113. tp->snd_ssthresh = tp->snd_cwnd_clamp;
  114. } else {
  115. /* ssthresh may have been reduced unnecessarily during.
  116. * 3WHS. Restore it back to its initial default.
  117. */
  118. tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
  119. }
  120. if (dst_metric(dst, RTAX_REORDERING) &&
  121. tp->reordering != dst_metric(dst, RTAX_REORDERING)) {
  122. tcp_disable_fack(tp);
  123. tcp_disable_early_retrans(tp);
  124. tp->reordering = dst_metric(dst, RTAX_REORDERING);
  125. }
  126. if (dst_metric(dst, RTAX_RTT) == 0 || tp->srtt == 0)
  127. goto reset;
  128. /* Initial rtt is determined from SYN,SYN-ACK.
  129. * The segment is small and rtt may appear much
  130. * less than real one. Use per-dst memory
  131. * to make it more realistic.
  132. *
  133. * A bit of theory. RTT is time passed after "normal" sized packet
  134. * is sent until it is ACKed. In normal circumstances sending small
  135. * packets force peer to delay ACKs and calculation is correct too.
  136. * The algorithm is adaptive and, provided we follow specs, it
  137. * NEVER underestimate RTT. BUT! If peer tries to make some clever
  138. * tricks sort of "quick acks" for time long enough to decrease RTT
  139. * to low value, and then abruptly stops to do it and starts to delay
  140. * ACKs, wait for troubles.
  141. */
  142. if (dst_metric_rtt(dst, RTAX_RTT) > tp->srtt) {
  143. tp->srtt = dst_metric_rtt(dst, RTAX_RTT);
  144. tp->rtt_seq = tp->snd_nxt;
  145. }
  146. if (dst_metric_rtt(dst, RTAX_RTTVAR) > tp->mdev) {
  147. tp->mdev = dst_metric_rtt(dst, RTAX_RTTVAR);
  148. tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
  149. }
  150. tcp_set_rto(sk);
  151. reset:
  152. if (tp->srtt == 0) {
  153. /* RFC6298: 5.7 We've failed to get a valid RTT sample from
  154. * 3WHS. This is most likely due to retransmission,
  155. * including spurious one. Reset the RTO back to 3secs
  156. * from the more aggressive 1sec to avoid more spurious
  157. * retransmission.
  158. */
  159. tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_FALLBACK;
  160. inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK;
  161. }
  162. /* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been
  163. * retransmitted. In light of RFC6298 more aggressive 1sec
  164. * initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK
  165. * retransmission has occurred.
  166. */
  167. if (tp->total_retrans > 1)
  168. tp->snd_cwnd = 1;
  169. else
  170. tp->snd_cwnd = tcp_init_cwnd(tp, dst);
  171. tp->snd_cwnd_stamp = tcp_time_stamp;
  172. }
  173. bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst)
  174. {
  175. if (!dst)
  176. return false;
  177. return dst_metric(dst, RTAX_RTT) ? true : false;
  178. }
  179. EXPORT_SYMBOL_GPL(tcp_peer_is_proven);