Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'simplify-TCP-loss-marking-code'

Yuchung Cheng says:

====================
simplify TCP loss marking code

The TCP loss marking is implemented by a set of intertwined
subroutines. TCP has several loss detection algorithms
(RACK, RFC6675/FACK, NewReno, etc) each calls a subset of
these routines to mark a packet lost. This has led to
various bugs (and fixes and fixes of fixes).

This patch set is to consolidate the loss marking code so
all detection algorithms call the same routine tcp_mark_skb_lost().
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+23 -53
+22 -38
net/ipv4/tcp_input.c
··· 1006 1006 ts ? LINUX_MIB_TCPTSREORDER : LINUX_MIB_TCPSACKREORDER); 1007 1007 } 1008 1008 1009 - /* This must be called before lost_out is incremented */ 1009 + /* This must be called before lost_out or retrans_out are updated 1010 + * on a new loss, because we want to know if all skbs previously 1011 + * known to be lost have already been retransmitted, indicating 1012 + * that this newly lost skb is our next skb to retransmit. 1013 + */ 1010 1014 static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb) 1011 1015 { 1012 1016 if ((!tp->retransmit_skb_hint && tp->retrans_out >= tp->lost_out) || ··· 1020 1016 tp->retransmit_skb_hint = skb; 1021 1017 } 1022 1018 1023 - /* Sum the number of packets on the wire we have marked as lost. 1024 - * There are two cases we care about here: 1025 - * a) Packet hasn't been marked lost (nor retransmitted), 1026 - * and this is the first loss. 1027 - * b) Packet has been marked both lost and retransmitted, 1028 - * and this means we think it was lost again. 1029 - */ 1030 - static void tcp_sum_lost(struct tcp_sock *tp, struct sk_buff *skb) 1019 + void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb) 1031 1020 { 1032 1021 __u8 sacked = TCP_SKB_CB(skb)->sacked; 1022 + struct tcp_sock *tp = tcp_sk(sk); 1033 1023 1034 - if (!(sacked & TCPCB_LOST) || 1035 - ((sacked & TCPCB_LOST) && (sacked & TCPCB_SACKED_RETRANS))) 1036 - tp->lost += tcp_skb_pcount(skb); 1037 - } 1024 + if (sacked & TCPCB_SACKED_ACKED) 1025 + return; 1038 1026 1039 - static void tcp_skb_mark_lost(struct tcp_sock *tp, struct sk_buff *skb) 1040 - { 1041 - if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) { 1042 - tcp_verify_retransmit_hint(tp, skb); 1043 - 1044 - tp->lost_out += tcp_skb_pcount(skb); 1045 - tcp_sum_lost(tp, skb); 1046 - TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; 1047 - } 1048 - } 1049 - 1050 - void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb) 1051 - { 1052 1027 tcp_verify_retransmit_hint(tp, skb); 1053 - 1054 - tcp_sum_lost(tp, skb); 1055 - if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) { 1028 + if (sacked & TCPCB_LOST) { 1029 + if (sacked & TCPCB_SACKED_RETRANS) { 1030 + /* Account for retransmits that are lost again */ 1031 + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; 1032 + tp->retrans_out -= tcp_skb_pcount(skb); 1033 + NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT, 1034 + tcp_skb_pcount(skb)); 1035 + } 1036 + } else { 1056 1037 tp->lost_out += tcp_skb_pcount(skb); 1057 1038 TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; 1058 1039 } ··· 2297 2308 if (cnt > packets) 2298 2309 break; 2299 2310 2300 - tcp_skb_mark_lost(tp, skb); 2311 + if (!(TCP_SKB_CB(skb)->sacked & TCPCB_LOST)) 2312 + tcp_mark_skb_lost(sk, skb); 2301 2313 2302 2314 if (mark_head) 2303 2315 break; ··· 2664 2674 unsigned int mss = tcp_current_mss(sk); 2665 2675 2666 2676 skb_rbtree_walk(skb, &sk->tcp_rtx_queue) { 2667 - if (tcp_skb_seglen(skb) > mss && 2668 - !(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { 2669 - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { 2670 - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; 2671 - tp->retrans_out -= tcp_skb_pcount(skb); 2672 - } 2673 - tcp_skb_mark_lost_uncond_verify(tp, skb); 2674 - } 2677 + if (tcp_skb_seglen(skb) > mss) 2678 + tcp_mark_skb_lost(sk, skb); 2675 2679 } 2676 2680 2677 2681 tcp_clear_retrans_hints_partial(tp);
+1 -15
net/ipv4/tcp_recovery.c
··· 2 2 #include <linux/tcp.h> 3 3 #include <net/tcp.h> 4 4 5 - void tcp_mark_skb_lost(struct sock *sk, struct sk_buff *skb) 6 - { 7 - struct tcp_sock *tp = tcp_sk(sk); 8 - 9 - tcp_skb_mark_lost_uncond_verify(tp, skb); 10 - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { 11 - /* Account for retransmits that are lost again */ 12 - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; 13 - tp->retrans_out -= tcp_skb_pcount(skb); 14 - NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT, 15 - tcp_skb_pcount(skb)); 16 - } 17 - } 18 - 19 5 static bool tcp_rack_sent_after(u64 t1, u64 t2, u32 seq1, u32 seq2) 20 6 { 21 7 return t1 > t2 || (t1 == t2 && after(seq1, seq2)); ··· 232 246 tcp_fragment(sk, TCP_FRAG_IN_RTX_QUEUE, skb, 233 247 mss, mss, GFP_ATOMIC); 234 248 235 - tcp_skb_mark_lost_uncond_verify(tp, skb); 249 + tcp_mark_skb_lost(sk, skb); 236 250 } 237 251 }