diff options
Diffstat (limited to 'net/ipv4/tcp_metrics.c')
-rw-r--r-- | net/ipv4/tcp_metrics.c | 42 |
1 files changed, 17 insertions, 25 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index f6a005c485a9..4a22f3e715df 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
@@ -443,7 +443,7 @@ void tcp_init_metrics(struct sock *sk) | |||
443 | struct dst_entry *dst = __sk_dst_get(sk); | 443 | struct dst_entry *dst = __sk_dst_get(sk); |
444 | struct tcp_sock *tp = tcp_sk(sk); | 444 | struct tcp_sock *tp = tcp_sk(sk); |
445 | struct tcp_metrics_block *tm; | 445 | struct tcp_metrics_block *tm; |
446 | u32 val; | 446 | u32 val, crtt = 0; /* cached RTT scaled by 8 */ |
447 | 447 | ||
448 | if (dst == NULL) | 448 | if (dst == NULL) |
449 | goto reset; | 449 | goto reset; |
@@ -478,15 +478,19 @@ void tcp_init_metrics(struct sock *sk) | |||
478 | tp->reordering = val; | 478 | tp->reordering = val; |
479 | } | 479 | } |
480 | 480 | ||
481 | val = tcp_metric_get(tm, TCP_METRIC_RTT); | 481 | crtt = tcp_metric_get_jiffies(tm, TCP_METRIC_RTT); |
482 | if (val == 0 || tp->srtt == 0) { | 482 | rcu_read_unlock(); |
483 | rcu_read_unlock(); | 483 | reset: |
484 | goto reset; | 484 | /* The initial RTT measurement from the SYN/SYN-ACK is not ideal |
485 | } | 485 | * to seed the RTO for later data packets because SYN packets are |
486 | /* Initial rtt is determined from SYN,SYN-ACK. | 486 | * small. Use the per-dst cached values to seed the RTO but keep |
487 | * The segment is small and rtt may appear much | 487 | * the RTT estimator variables intact (e.g., srtt, mdev, rttvar). |
488 | * less than real one. Use per-dst memory | 488 | * Later the RTO will be updated immediately upon obtaining the first |
489 | * to make it more realistic. | 489 | * data RTT sample (tcp_rtt_estimator()). Hence the cached RTT only |
490 | * influences the first RTO but not later RTT estimation. | ||
491 | * | ||
492 | * But if RTT is not available from the SYN (due to retransmits or | ||
493 | * syn cookies) or the cache, force a conservative 3secs timeout. | ||
490 | * | 494 | * |
491 | * A bit of theory. RTT is time passed after "normal" sized packet | 495 | * A bit of theory. RTT is time passed after "normal" sized packet |
492 | * is sent until it is ACKed. In normal circumstances sending small | 496 | * is sent until it is ACKed. In normal circumstances sending small |
@@ -497,21 +501,9 @@ void tcp_init_metrics(struct sock *sk) | |||
497 | * to low value, and then abruptly stops to do it and starts to delay | 501 | * to low value, and then abruptly stops to do it and starts to delay |
498 | * ACKs, wait for troubles. | 502 | * ACKs, wait for troubles. |
499 | */ | 503 | */ |
500 | val = msecs_to_jiffies(val); | 504 | if (crtt > tp->srtt) { |
501 | if (val > tp->srtt) { | 505 | inet_csk(sk)->icsk_rto = crtt + max(crtt >> 2, tcp_rto_min(sk)); |
502 | tp->srtt = val; | 506 | } else if (tp->srtt == 0) { |
503 | tp->rtt_seq = tp->snd_nxt; | ||
504 | } | ||
505 | val = tcp_metric_get_jiffies(tm, TCP_METRIC_RTTVAR); | ||
506 | if (val > tp->mdev) { | ||
507 | tp->mdev = val; | ||
508 | tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk)); | ||
509 | } | ||
510 | rcu_read_unlock(); | ||
511 | |||
512 | tcp_set_rto(sk); | ||
513 | reset: | ||
514 | if (tp->srtt == 0) { | ||
515 | /* RFC6298: 5.7 We've failed to get a valid RTT sample from | 507 | /* RFC6298: 5.7 We've failed to get a valid RTT sample from |
516 | * 3WHS. This is most likely due to retransmission, | 508 | * 3WHS. This is most likely due to retransmission, |
517 | * including spurious one. Reset the RTO back to 3secs | 509 | * including spurious one. Reset the RTO back to 3secs |