git: 1a70101a8700 - main - tcp: account sent/received IP ECN markings independently

From: Richard Scheffenegger <rscheff_at_FreeBSD.org>
Date: Thu, 10 Nov 2022 11:09:50 UTC
The branch main has been updated by rscheff:

URL: https://cgit.FreeBSD.org/src/commit/?id=1a70101a870015304d5b2446b480d8677d8aad36

commit 1a70101a870015304d5b2446b480d8677d8aad36
Author:     Richard Scheffenegger <rscheff@FreeBSD.org>
AuthorDate: 2022-11-10 10:35:02 +0000
Commit:     Richard Scheffenegger <rscheff@FreeBSD.org>
CommitDate: 2022-11-10 10:35:35 +0000

    tcp: account sent/received IP ECN markings independently
    
    Have tcpstats (netstat -s) differentiate between received and sent
    ECN-marked packets. Also account for IP ECN bits (on TCP packets)
    even when the tcp session has not negotiated ECN support.
    
    Event:                  IETF 115 Hackathon
    Reviewed By:            glebius, tuexen, #transport
    Sponsored by:           NetApp, Inc.
    Differential Revision:  https://reviews.freebsd.org/D37314
---
 sys/netinet/tcp_ecn.c  | 40 ++++++++++++++++++++++++++--------------
 sys/netinet/tcp_var.h  | 12 ++++++++----
 usr.bin/netstat/inet.c | 16 ++++++++++------
 3 files changed, 44 insertions(+), 24 deletions(-)

diff --git a/sys/netinet/tcp_ecn.c b/sys/netinet/tcp_ecn.c
index 8e3e38ddabfc..5b19ed93225f 100644
--- a/sys/netinet/tcp_ecn.c
+++ b/sys/netinet/tcp_ecn.c
@@ -288,19 +288,19 @@ tcp_ecn_input_segment(struct tcpcb *tp, uint16_t thflags, int tlen, int pkts, in
 {
 	int delta_cep = 0;
 
-	if (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT)) {
-		switch (iptos & IPTOS_ECN_MASK) {
-		case IPTOS_ECN_CE:
-			TCPSTAT_INC(tcps_ecn_ce);
-			break;
-		case IPTOS_ECN_ECT0:
-			TCPSTAT_INC(tcps_ecn_ect0);
-			break;
-		case IPTOS_ECN_ECT1:
-			TCPSTAT_INC(tcps_ecn_ect1);
-			break;
-		}
+	switch (iptos & IPTOS_ECN_MASK) {
+	case IPTOS_ECN_CE:
+		TCPSTAT_INC(tcps_ecn_rcvce);
+		break;
+	case IPTOS_ECN_ECT0:
+		TCPSTAT_INC(tcps_ecn_rcvect0);
+		break;
+	case IPTOS_ECN_ECT1:
+		TCPSTAT_INC(tcps_ecn_rcvect1);
+		break;
+	}
 
+	if (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT)) {
 		if (tp->t_flags2 & TF2_ACE_PERMIT) {
 			if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
 				tp->t_rcep += 1;
@@ -413,10 +413,10 @@ tcp_ecn_output_established(struct tcpcb *tp, uint16_t *thflags, int len, bool rx
 	if (newdata) {
 		if (tp->t_flags2 & TF2_ECN_USE_ECT1) {
 			ipecn = IPTOS_ECN_ECT1;
-			TCPSTAT_INC(tcps_ecn_ect1);
+			TCPSTAT_INC(tcps_ecn_sndect1);
 		} else {
 			ipecn = IPTOS_ECN_ECT0;
-			TCPSTAT_INC(tcps_ecn_ect0);
+			TCPSTAT_INC(tcps_ecn_sndect0);
 		}
 	}
 	/*
@@ -497,6 +497,18 @@ tcp_ecn_syncache_add(uint16_t thflags, int iptos)
 {
 	int scflags = 0;
 
+	switch (iptos & IPTOS_ECN_MASK) {
+	case IPTOS_ECN_CE:
+		TCPSTAT_INC(tcps_ecn_rcvce);
+		break;
+	case IPTOS_ECN_ECT0:
+		TCPSTAT_INC(tcps_ecn_rcvect0);
+		break;
+	case IPTOS_ECN_ECT1:
+		TCPSTAT_INC(tcps_ecn_rcvect1);
+		break;
+	}
+
 	switch (thflags & (TH_AE|TH_CWR|TH_ECE)) {
 	/* no ECN */
 	case (0|0|0):
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 2cfc1ff3f21a..3cfbad75085d 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -787,9 +787,9 @@ struct	tcpstat {
 	uint64_t tcps_sack_sboverflow;	    /* times scoreboard overflowed */
 
 	/* ECN related stats */
-	uint64_t tcps_ecn_ce;		/* ECN Congestion Experienced */
-	uint64_t tcps_ecn_ect0;		/* ECN Capable Transport */
-	uint64_t tcps_ecn_ect1;		/* ECN Capable Transport */
+	uint64_t tcps_ecn_rcvce;		/* ECN Congestion Experienced */
+	uint64_t tcps_ecn_rcvect0;		/* ECN Capable Transport */
+	uint64_t tcps_ecn_rcvect1;		/* ECN Capable Transport */
 	uint64_t tcps_ecn_shs;		/* ECN successful handshakes */
 	uint64_t tcps_ecn_rcwnd;	/* # times ECN reduced the cwnd */
 
@@ -824,7 +824,11 @@ struct	tcpstat {
 	uint64_t tcps_ace_ect0;		/* ACE SYN packet with ECT0 */
 	uint64_t tcps_ace_ce;		/* ACE SYN packet with CE */
 
-	uint64_t _pad[6];		/* 6 TBD placeholder for STABLE */
+	/* ECN related stats */
+	uint64_t tcps_ecn_sndect0;		/* ECN Capable Transport */
+	uint64_t tcps_ecn_sndect1;		/* ECN Capable Transport */
+
+	uint64_t _pad[4];		/* 4 TBD placeholder for STABLE */
 };
 
 #define	tcps_rcvmemdrop	tcps_rcvreassfull	/* compat */
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index c295f34a96c6..a16f09d391fb 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -818,12 +818,16 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
 	xo_close_container("sack");
 	xo_open_container("ecn");
 
-	p(tcps_ecn_ce, "\t{:ce-packets/%ju} "
-	    "{N:/packet%s with ECN CE bit set}\n");
-	p(tcps_ecn_ect0, "\t{:ect0-packets/%ju} "
-	    "{N:/packet%s with ECN ECT(0) bit set}\n");
-	p(tcps_ecn_ect1, "\t{:ect1-packets/%ju} "
-	    "{N:/packet%s with ECN ECT(1) bit set}\n");
+	p(tcps_ecn_rcvce, "\t{:received-ce-packets/%ju} "
+	    "{N:/packet%s received with ECN CE bit set}\n");
+	p(tcps_ecn_rcvect0, "\t{:received-ect0-packets/%ju} "
+	    "{N:/packet%s received with ECN ECT(0) bit set}\n");
+	p(tcps_ecn_rcvect1, "\t{:received-ect1-packets/%ju} "
+	    "{N:/packet%s received with ECN ECT(1) bit set}\n");
+	p(tcps_ecn_sndect0, "\t{:sent-ect0-packets/%ju} "
+	    "{N:/packet%s sent with ECN ECT(0) bit set}\n");
+	p(tcps_ecn_sndect1, "\t{:sent-ect1-packets/%ju} "
+	    "{N:/packet%s sent with ECN ECT(1) bit set}\n");
 	p(tcps_ecn_shs, "\t{:handshakes/%ju} "
 	    "{N:/successful ECN handshake%s}\n");
 	p(tcps_ecn_rcwnd, "\t{:congestion-reductions/%ju} "