Author: rscheff
Date: Thu May 21 21:33:15 2020
New Revision: 361347
URL: https://svnweb.freebsd.org/changeset/base/361347

Log:
  With RFC3168 ECN, CWR SHOULD only be sent with new data
  
  Overly conservative data receivers may ignore the CWR flag
  on other packets, and keep ECE latched. This can result in
  continous reduction of the congestion window, and very poor
  performance when ECN is enabled.
  
  Reviewed by:  rgrimes (mentor), rrs
  Approved by:  rgrimes (mentor), tuexen (mentor)
  MFC after:    3 days
  Sponsored by: NetApp, Inc.
  Differential Revision:        https://reviews.freebsd.org/D23364

Modified:
  head/sys/netinet/tcp_input.c
  head/sys/netinet/tcp_output.c
  head/sys/netinet/tcp_stacks/rack.c

Modified: head/sys/netinet/tcp_input.c
==============================================================================
--- head/sys/netinet/tcp_input.c        Thu May 21 21:26:21 2020        
(r361346)
+++ head/sys/netinet/tcp_input.c        Thu May 21 21:33:15 2020        
(r361347)
@@ -447,9 +447,15 @@ cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, ui
                }
                break;
        case CC_ECN:
-               if (!IN_CONGRECOVERY(tp->t_flags)) {
+               if (!IN_CONGRECOVERY(tp->t_flags) ||
+                   /*
+                    * Allow ECN reaction on ACK to CWR, if
+                    * that data segment was also CE marked.
+                    */
+                   SEQ_GEQ(th->th_ack, tp->snd_recover)) {
+                       EXIT_CONGRECOVERY(tp->t_flags);
                        TCPSTAT_INC(tcps_ecn_rcwnd);
-                       tp->snd_recover = tp->snd_max;
+                       tp->snd_recover = tp->snd_max + 1;
                        if (tp->t_flags2 & TF2_ECN_PERMIT)
                                tp->t_flags2 |= TF2_ECN_SND_CWR;
                }

Modified: head/sys/netinet/tcp_output.c
==============================================================================
--- head/sys/netinet/tcp_output.c       Thu May 21 21:26:21 2020        
(r361346)
+++ head/sys/netinet/tcp_output.c       Thu May 21 21:33:15 2020        
(r361347)
@@ -1170,7 +1170,8 @@ send:
                 */
                if (len > 0 && SEQ_GEQ(tp->snd_nxt, tp->snd_max) &&
                    (sack_rxmit == 0) &&
-                   !((tp->t_flags & TF_FORCEDATA) && len == 1)) {
+                   !((tp->t_flags & TF_FORCEDATA) && len == 1 &&
+                   SEQ_LT(tp->snd_una, tp->snd_max))) {
 #ifdef INET6
                        if (isipv6)
                                ip6->ip6_flow |= htonl(IPTOS_ECN_ECT0 << 20);
@@ -1178,14 +1179,14 @@ send:
 #endif
                                ip->ip_tos |= IPTOS_ECN_ECT0;
                        TCPSTAT_INC(tcps_ecn_ect0);
-               }
-
-               /*
-                * Reply with proper ECN notifications.
-                */
-               if (tp->t_flags2 & TF2_ECN_SND_CWR) {
-                       flags |= TH_CWR;
-                       tp->t_flags2 &= ~TF2_ECN_SND_CWR;
+                       /*
+                        * Reply with proper ECN notifications.
+                        * Only set CWR on new data segments.
+                        */
+                       if (tp->t_flags2 & TF2_ECN_SND_CWR) {
+                               flags |= TH_CWR;
+                               tp->t_flags2 &= ~TF2_ECN_SND_CWR;
+                       }
                }
                if (tp->t_flags2 & TF2_ECN_SND_ECE)
                        flags |= TH_ECE;

Modified: head/sys/netinet/tcp_stacks/rack.c
==============================================================================
--- head/sys/netinet/tcp_stacks/rack.c  Thu May 21 21:26:21 2020        
(r361346)
+++ head/sys/netinet/tcp_stacks/rack.c  Thu May 21 21:33:15 2020        
(r361347)
@@ -4095,9 +4095,15 @@ rack_cong_signal(struct tcpcb *tp, struct tcphdr *th, 
                }
                break;
        case CC_ECN:
-               if (!IN_CONGRECOVERY(tp->t_flags)) {
+               if (!IN_CONGRECOVERY(tp->t_flags) ||
+                   /*
+                    * Allow ECN reaction on ACK to CWR, if
+                    * that data segment was also CE marked.
+                    */
+                   SEQ_GEQ(th->th_ack, tp->snd_recover)) {
+                       EXIT_CONGRECOVERY(tp->t_flags);
                        KMOD_TCPSTAT_INC(tcps_ecn_rcwnd);
-                       tp->snd_recover = tp->snd_max;
+                       tp->snd_recover = tp->snd_max + 1;
                        if (tp->t_flags2 & TF2_ECN_PERMIT)
                                tp->t_flags2 |= TF2_ECN_SND_CWR;
                }
@@ -13556,13 +13562,14 @@ send:
 #endif
                                ip->ip_tos |= IPTOS_ECN_ECT0;
                        KMOD_TCPSTAT_INC(tcps_ecn_ect0);
-               }
-               /*
-                * Reply with proper ECN notifications.
-                */
-               if (tp->t_flags2 & TF2_ECN_SND_CWR) {
-                       flags |= TH_CWR;
-                       tp->t_flags2 &= ~TF2_ECN_SND_CWR;
+                       /*
+                        * Reply with proper ECN notifications.
+                        * Only set CWR on new data segments.
+                        */
+                       if (tp->t_flags2 & TF2_ECN_SND_CWR) {
+                               flags |= TH_CWR;
+                               tp->t_flags2 &= ~TF2_ECN_SND_CWR;
+                       }
                }
                if (tp->t_flags2 & TF2_ECN_SND_ECE)
                        flags |= TH_ECE;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to