Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -153,11 +153,6 @@ &VNET_NAME(drop_synfin), 0, "Drop TCP packets with SYN+FIN set"); -VNET_DEFINE(int, tcp_do_prr_conservative) = 0; -SYSCTL_INT(_net_inet_tcp, OID_AUTO, do_prr_conservative, CTLFLAG_VNET | CTLFLAG_RW, - &VNET_NAME(tcp_do_prr_conservative), 0, - "Do conservative Proportional Rate Reduction"); - VNET_DEFINE(int, tcp_do_prr) = 1; SYSCTL_INT(_net_inet_tcp, OID_AUTO, do_prr, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_do_prr), 1, @@ -2575,7 +2570,11 @@ CC_DUPACK); if (V_tcp_do_prr && IN_FASTRECOVERY(tp->t_flags)) { - tcp_do_prr_ack(tp, th, &to); + /* + * While dealing with DupAcks, + * always use PRR-CRB + */ + tcp_do_prr_ack(tp, th, &to, 2); } else if ((tp->t_flags & TF_SACK_PERMIT) && (to.to_flags & TOF_SACK) && IN_FASTRECOVERY(tp->t_flags)) { @@ -2783,7 +2782,7 @@ if (V_tcp_do_prr && to.to_flags & TOF_SACK) { tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; - tcp_do_prr_ack(tp, th, &to); + tcp_do_prr_ack(tp, th, &to, sack_changed); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); } else @@ -2797,7 +2796,11 @@ if (V_tcp_do_prr) { tp->sackhint.delivered_data = BYTES_THIS_ACK(tp, th); tp->snd_fack = th->th_ack; - tcp_do_prr_ack(tp, th, &to); + /* + * During ECN cwnd reduction + * always use PRR-SSRB + */ + tcp_do_prr_ack(tp, th, &to, 1); (void) tcp_output(tp); } } else @@ -3926,7 +3929,7 @@ } void -tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to) +tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, int sack_changed) { int snd_cnt = 0, limit = 0, del_data = 0, pipe = 0; int maxseg = tcp_maxseg(tp); @@ -3967,7 +3970,17 @@ tp->snd_ssthresh, tp->sackhint.recover_fs) - tp->sackhint.prr_out; } else { - if (V_tcp_do_prr_conservative || (del_data == 0)) + /* + * PRR 6937bis heuristic: + * - A partial ack without SACK block beneath snd_recover + * indicates further loss. + * - An SACK scoreboard update adding a new hole indicates + * further loss, so be conservative and send at most one + * segment. + * - Prevent ACK splitting attacks, by being conservative + * when no new data is acked. + */ + if ((sack_changed == 2) || (del_data == 0)) limit = tp->sackhint.prr_delivered - tp->sackhint.prr_out; else Index: sys/netinet/tcp_sack.c =================================================================== --- sys/netinet/tcp_sack.c +++ sys/netinet/tcp_sack.c @@ -533,7 +533,8 @@ * Process cumulative ACK and the TCP SACK option to update the scoreboard. * tp->snd_holes is an ordered list of holes (oldest to newest, in terms of * the sequence space). - * Returns 1 if incoming ACK has previously unknown SACK information, + * Returns 2 if incoming ACK indicates ongoing loss (hole split, new hole), + * 1 if incoming ACK has previously unknown SACK information, * 0 otherwise. */ int @@ -639,7 +640,7 @@ tp->snd_fack = sblkp->end; /* Go to the previous sack block. */ sblkp--; - sack_changed = 1; + sack_changed = 2; } else { /* * We failed to add a new hole based on the current @@ -656,7 +657,12 @@ SEQ_LT(tp->snd_fack, sblkp->end)) { delivered_data += sblkp->end - tp->snd_fack; tp->snd_fack = sblkp->end; - sack_changed = 1; + /* + * While the Scoreboard didn't change in + * size, we only ended up here because + * some SACK data had to be dismissed. + */ + sack_changed = 2; } } } else if (SEQ_LT(tp->snd_fack, sblkp->end)) { @@ -725,6 +731,7 @@ */ temp = tcp_sackhole_insert(tp, sblkp->end, cur->end, cur); + sack_changed = 2; if (temp != NULL) { if (SEQ_GT(cur->rxmit, temp->rxmit)) { temp->rxmit = cur->rxmit; Index: sys/netinet/tcp_var.h =================================================================== --- sys/netinet/tcp_var.h +++ sys/netinet/tcp_var.h @@ -871,7 +871,6 @@ VNET_DECLARE(struct inpcbinfo, tcbinfo); #define V_tcp_do_prr VNET(tcp_do_prr) -#define V_tcp_do_prr_conservative VNET(tcp_do_prr_conservative) #define V_tcp_do_newcwv VNET(tcp_do_newcwv) #define V_drop_synfin VNET(drop_synfin) #define V_path_mtu_discovery VNET(path_mtu_discovery) @@ -1065,7 +1064,7 @@ void tcp_clean_sackreport(struct tcpcb *tp); void tcp_sack_adjust(struct tcpcb *tp); struct sackhole *tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt); -void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *); +void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *, int); void tcp_sack_partialack(struct tcpcb *, struct tcphdr *); void tcp_free_sackholes(struct tcpcb *tp); int tcp_newreno(struct tcpcb *, struct tcphdr *);