Loading include/linux/tcp.h +1 −1 Original line number Diff line number Diff line Loading @@ -330,7 +330,7 @@ struct tcp_sock { struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ struct tcp_sack_block_wire recv_sack_cache[4]; struct tcp_sack_block recv_sack_cache[4]; struct sk_buff *highest_sack; /* highest skb with SACK received * (validity guaranteed only if Loading net/ipv4/tcp_input.c +51 −34 Original line number Diff line number Diff line Loading @@ -1340,9 +1340,11 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ struct tcp_sock *tp = tcp_sk(sk); unsigned char *ptr = (skb_transport_header(ack_skb) + TCP_SKB_CB(ack_skb)->sacked); struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2); struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2); struct tcp_sack_block sp[4]; struct sk_buff *cached_skb; int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; int used_sacks; int reord = tp->packets_out; int flag = 0; int found_dup_sack = 0; Loading @@ -1357,7 +1359,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ tp->highest_sack = tcp_write_queue_head(sk); } found_dup_sack = tcp_check_dsack(tp, ack_skb, sp, found_dup_sack = tcp_check_dsack(tp, ack_skb, sp_wire, num_sacks, prior_snd_una); if (found_dup_sack) flag |= FLAG_DSACKING_ACK; Loading @@ -1372,14 +1374,49 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (!tp->packets_out) goto out; used_sacks = 0; first_sack_index = 0; for (i = 0; i < num_sacks; i++) { int dup_sack = !i && found_dup_sack; sp[used_sacks].start_seq = ntohl(get_unaligned(&sp_wire[i].start_seq)); sp[used_sacks].end_seq = ntohl(get_unaligned(&sp_wire[i].end_seq)); if (!tcp_is_sackblock_valid(tp, dup_sack, sp[used_sacks].start_seq, sp[used_sacks].end_seq)) { if (dup_sack) { if (!tp->undo_marker) NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); else NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); } else { /* Don't count olds caused by ACK reordering */ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && !after(sp[used_sacks].end_seq, tp->snd_una)) continue; NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); } if (i == 0) first_sack_index = -1; continue; } /* Ignore very old stuff early */ if (!after(sp[used_sacks].end_seq, prior_snd_una)) continue; used_sacks++; } /* SACK fastpath: * if the only SACK change is the increase of the end_seq of * the first block then only apply that SACK block * and use retrans queue hinting otherwise slowpath */ force_one_sack = 1; for (i = 0; i < num_sacks; i++) { __be32 start_seq = sp[i].start_seq; __be32 end_seq = sp[i].end_seq; for (i = 0; i < used_sacks; i++) { u32 start_seq = sp[i].start_seq; u32 end_seq = sp[i].end_seq; if (i == 0) { if (tp->recv_sack_cache[i].start_seq != start_seq) Loading @@ -1398,19 +1435,17 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ tp->recv_sack_cache[i].end_seq = 0; } first_sack_index = 0; if (force_one_sack) num_sacks = 1; used_sacks = 1; else { int j; tp->fastpath_skb_hint = NULL; /* order SACK blocks to allow in order walk of the retrans queue */ for (i = num_sacks-1; i > 0; i--) { for (i = used_sacks - 1; i > 0; i--) { for (j = 0; j < i; j++){ if (after(ntohl(sp[j].start_seq), ntohl(sp[j+1].start_seq))){ struct tcp_sack_block_wire tmp; if (after(sp[j].start_seq, sp[j+1].start_seq)) { struct tcp_sack_block tmp; tmp = sp[j]; sp[j] = sp[j+1]; Loading @@ -1433,32 +1468,14 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ cached_fack_count = 0; } for (i = 0; i < num_sacks; i++) { for (i = 0; i < used_sacks; i++) { struct sk_buff *skb; __u32 start_seq = ntohl(sp->start_seq); __u32 end_seq = ntohl(sp->end_seq); u32 start_seq = sp[i].start_seq; u32 end_seq = sp[i].end_seq; int fack_count; int dup_sack = (found_dup_sack && (i == first_sack_index)); int next_dup = (found_dup_sack && (i+1 == first_sack_index)); sp++; if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) { if (dup_sack) { if (!tp->undo_marker) NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); else NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); } else { /* Don't count olds caused by ACK reordering */ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && !after(end_seq, tp->snd_una)) continue; NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); } continue; } skb = cached_skb; fack_count = cached_fack_count; Loading Loading @@ -1489,8 +1506,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ /* Due to sorting DSACK may reside within this SACK block! */ if (next_dup) { u32 dup_start = ntohl(sp->start_seq); u32 dup_end = ntohl(sp->end_seq); u32 dup_start = sp[i+1].start_seq; u32 dup_end = sp[i+1].end_seq; if (before(TCP_SKB_CB(skb)->seq, dup_end)) { in_sack = tcp_match_skb_to_sack(sk, skb, dup_start, dup_end); Loading Loading
include/linux/tcp.h +1 −1 Original line number Diff line number Diff line Loading @@ -330,7 +330,7 @@ struct tcp_sock { struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ struct tcp_sack_block_wire recv_sack_cache[4]; struct tcp_sack_block recv_sack_cache[4]; struct sk_buff *highest_sack; /* highest skb with SACK received * (validity guaranteed only if Loading
net/ipv4/tcp_input.c +51 −34 Original line number Diff line number Diff line Loading @@ -1340,9 +1340,11 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ struct tcp_sock *tp = tcp_sk(sk); unsigned char *ptr = (skb_transport_header(ack_skb) + TCP_SKB_CB(ack_skb)->sacked); struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2); struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2); struct tcp_sack_block sp[4]; struct sk_buff *cached_skb; int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; int used_sacks; int reord = tp->packets_out; int flag = 0; int found_dup_sack = 0; Loading @@ -1357,7 +1359,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ tp->highest_sack = tcp_write_queue_head(sk); } found_dup_sack = tcp_check_dsack(tp, ack_skb, sp, found_dup_sack = tcp_check_dsack(tp, ack_skb, sp_wire, num_sacks, prior_snd_una); if (found_dup_sack) flag |= FLAG_DSACKING_ACK; Loading @@ -1372,14 +1374,49 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (!tp->packets_out) goto out; used_sacks = 0; first_sack_index = 0; for (i = 0; i < num_sacks; i++) { int dup_sack = !i && found_dup_sack; sp[used_sacks].start_seq = ntohl(get_unaligned(&sp_wire[i].start_seq)); sp[used_sacks].end_seq = ntohl(get_unaligned(&sp_wire[i].end_seq)); if (!tcp_is_sackblock_valid(tp, dup_sack, sp[used_sacks].start_seq, sp[used_sacks].end_seq)) { if (dup_sack) { if (!tp->undo_marker) NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); else NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); } else { /* Don't count olds caused by ACK reordering */ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && !after(sp[used_sacks].end_seq, tp->snd_una)) continue; NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); } if (i == 0) first_sack_index = -1; continue; } /* Ignore very old stuff early */ if (!after(sp[used_sacks].end_seq, prior_snd_una)) continue; used_sacks++; } /* SACK fastpath: * if the only SACK change is the increase of the end_seq of * the first block then only apply that SACK block * and use retrans queue hinting otherwise slowpath */ force_one_sack = 1; for (i = 0; i < num_sacks; i++) { __be32 start_seq = sp[i].start_seq; __be32 end_seq = sp[i].end_seq; for (i = 0; i < used_sacks; i++) { u32 start_seq = sp[i].start_seq; u32 end_seq = sp[i].end_seq; if (i == 0) { if (tp->recv_sack_cache[i].start_seq != start_seq) Loading @@ -1398,19 +1435,17 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ tp->recv_sack_cache[i].end_seq = 0; } first_sack_index = 0; if (force_one_sack) num_sacks = 1; used_sacks = 1; else { int j; tp->fastpath_skb_hint = NULL; /* order SACK blocks to allow in order walk of the retrans queue */ for (i = num_sacks-1; i > 0; i--) { for (i = used_sacks - 1; i > 0; i--) { for (j = 0; j < i; j++){ if (after(ntohl(sp[j].start_seq), ntohl(sp[j+1].start_seq))){ struct tcp_sack_block_wire tmp; if (after(sp[j].start_seq, sp[j+1].start_seq)) { struct tcp_sack_block tmp; tmp = sp[j]; sp[j] = sp[j+1]; Loading @@ -1433,32 +1468,14 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ cached_fack_count = 0; } for (i = 0; i < num_sacks; i++) { for (i = 0; i < used_sacks; i++) { struct sk_buff *skb; __u32 start_seq = ntohl(sp->start_seq); __u32 end_seq = ntohl(sp->end_seq); u32 start_seq = sp[i].start_seq; u32 end_seq = sp[i].end_seq; int fack_count; int dup_sack = (found_dup_sack && (i == first_sack_index)); int next_dup = (found_dup_sack && (i+1 == first_sack_index)); sp++; if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) { if (dup_sack) { if (!tp->undo_marker) NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDNOUNDO); else NET_INC_STATS_BH(LINUX_MIB_TCPDSACKIGNOREDOLD); } else { /* Don't count olds caused by ACK reordering */ if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && !after(end_seq, tp->snd_una)) continue; NET_INC_STATS_BH(LINUX_MIB_TCPSACKDISCARD); } continue; } skb = cached_skb; fack_count = cached_fack_count; Loading Loading @@ -1489,8 +1506,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ /* Due to sorting DSACK may reside within this SACK block! */ if (next_dup) { u32 dup_start = ntohl(sp->start_seq); u32 dup_end = ntohl(sp->end_seq); u32 dup_start = sp[i+1].start_seq; u32 dup_end = sp[i+1].end_seq; if (before(TCP_SKB_CB(skb)->seq, dup_end)) { in_sack = tcp_match_skb_to_sack(sk, skb, dup_start, dup_end); Loading