Skip to content

Commit f745664

Browse files
edumazetdavem330
authored andcommitted
tcp: add tcp_ld_RTO_revert() helper
RFC 6069 logic has been implemented for IPv4 only so far, right in the middle of tcp_v4_err() and was error prone. Move this code to one helper, to make tcp_v4_err() more readable and to eventually expand RFC 6069 to IPv6 in the future. Also perform sock_owned_by_user() check a bit sooner. Signed-off-by: Eric Dumazet <[email protected]> Acked-by: Neal Cardwell <[email protected]> Tested-by: Neal Cardwell <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d6a3511 commit f745664

File tree

1 file changed

+45
-40
lines changed

1 file changed

+45
-40
lines changed

net/ipv4/tcp_ipv4.c

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,45 @@ void tcp_req_err(struct sock *sk, u32 seq, bool abort)
403403
}
404404
EXPORT_SYMBOL(tcp_req_err);
405405

406+
/* TCP-LD (RFC 6069) logic */
407+
static void tcp_ld_RTO_revert(struct sock *sk, u32 seq)
408+
{
409+
struct inet_connection_sock *icsk = inet_csk(sk);
410+
struct tcp_sock *tp = tcp_sk(sk);
411+
struct sk_buff *skb;
412+
s32 remaining;
413+
u32 delta_us;
414+
415+
if (sock_owned_by_user(sk))
416+
return;
417+
418+
if (seq != tp->snd_una || !icsk->icsk_retransmits ||
419+
!icsk->icsk_backoff)
420+
return;
421+
422+
skb = tcp_rtx_queue_head(sk);
423+
if (WARN_ON_ONCE(!skb))
424+
return;
425+
426+
icsk->icsk_backoff--;
427+
icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) : TCP_TIMEOUT_INIT;
428+
icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX);
429+
430+
tcp_mstamp_refresh(tp);
431+
delta_us = (u32)(tp->tcp_mstamp - tcp_skb_timestamp_us(skb));
432+
remaining = icsk->icsk_rto - usecs_to_jiffies(delta_us);
433+
434+
if (remaining > 0) {
435+
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
436+
remaining, TCP_RTO_MAX);
437+
} else {
438+
/* RTO revert clocked out retransmission.
439+
* Will retransmit now.
440+
*/
441+
tcp_retransmit_timer(sk);
442+
}
443+
}
444+
406445
/*
407446
* This routine is called by the ICMP module when it gets some
408447
* sort of error condition. If err < 0 then the socket should
@@ -423,17 +462,13 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
423462
{
424463
const struct iphdr *iph = (const struct iphdr *)icmp_skb->data;
425464
struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2));
426-
struct inet_connection_sock *icsk;
427465
struct tcp_sock *tp;
428466
struct inet_sock *inet;
429467
const int type = icmp_hdr(icmp_skb)->type;
430468
const int code = icmp_hdr(icmp_skb)->code;
431469
struct sock *sk;
432-
struct sk_buff *skb;
433470
struct request_sock *fastopen;
434471
u32 seq, snd_una;
435-
s32 remaining;
436-
u32 delta_us;
437472
int err;
438473
struct net *net = dev_net(icmp_skb->dev);
439474

@@ -476,7 +511,6 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
476511
goto out;
477512
}
478513

479-
icsk = inet_csk(sk);
480514
tp = tcp_sk(sk);
481515
/* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
482516
fastopen = rcu_dereference(tp->fastopen_rsk);
@@ -521,41 +555,12 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
521555
}
522556

523557
err = icmp_err_convert[code].errno;
524-
/* check if icmp_skb allows revert of backoff
525-
* (see draft-zimmermann-tcp-lcd) */
526-
if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH)
527-
break;
528-
if (seq != tp->snd_una || !icsk->icsk_retransmits ||
529-
!icsk->icsk_backoff || fastopen)
530-
break;
531-
532-
if (sock_owned_by_user(sk))
533-
break;
534-
535-
skb = tcp_rtx_queue_head(sk);
536-
if (WARN_ON_ONCE(!skb))
537-
break;
538-
539-
icsk->icsk_backoff--;
540-
icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) :
541-
TCP_TIMEOUT_INIT;
542-
icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX);
543-
544-
545-
tcp_mstamp_refresh(tp);
546-
delta_us = (u32)(tp->tcp_mstamp - tcp_skb_timestamp_us(skb));
547-
remaining = icsk->icsk_rto -
548-
usecs_to_jiffies(delta_us);
549-
550-
if (remaining > 0) {
551-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
552-
remaining, TCP_RTO_MAX);
553-
} else {
554-
/* RTO revert clocked out retransmission.
555-
* Will retransmit now */
556-
tcp_retransmit_timer(sk);
557-
}
558-
558+
/* check if this ICMP message allows revert of backoff.
559+
* (see RFC 6069)
560+
*/
561+
if (!fastopen &&
562+
(code == ICMP_NET_UNREACH || code == ICMP_HOST_UNREACH))
563+
tcp_ld_RTO_revert(sk, seq);
559564
break;
560565
case ICMP_TIME_EXCEEDED:
561566
err = EHOSTUNREACH;

0 commit comments

Comments
 (0)