From 570c2dafb039b2a1f1383fa5a26b89fb0a12c18d Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
Date: Sun, 20 Nov 2016 18:29:44 +0100
Subject: [PATCH] Allow the TS ecr value to be absolute.

This is based on a patch from Jason Eggleston with minor modifications
from me.
---
 gtests/net/packetdrill/packet.h     |  7 ++++---
 gtests/net/packetdrill/parser.y     | 29 +++++++++++++++++++++++------
 gtests/net/packetdrill/run_packet.c |  6 +++++-
 gtests/net/packetdrill/tcp_packet.c |  5 +++++
 gtests/net/packetdrill/tcp_packet.h |  1 +
 gtests/net/packetdrill/types.h      |  8 ++++++++
 6 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/gtests/net/packetdrill/packet.h b/gtests/net/packetdrill/packet.h
index a51c9e11..a7510b34 100644
--- a/gtests/net/packetdrill/packet.h
+++ b/gtests/net/packetdrill/packet.h
@@ -108,9 +108,10 @@ struct packet {
 	u32 flags;		  /* various meta-flags */
 #define FLAG_WIN_NOCHECK          0x1  /* don't check TCP receive window */
 #define FLAG_OPTIONS_NOCHECK      0x2  /* don't check TCP options */
-#define FLAGS_SCTP_BAD_CRC32C     0x4  /* compute bad CRC32C for SCTP packets */
-#define FLAGS_SCTP_EXPLICIT_TAG   0x8  /* verification tag specified */
-#define FLAGS_SCTP_GENERIC_PACKET 0x10 /* set if it is a generic packet */
+#define FLAG_ABSOLUTE_TS_ECR      0x4  /* don't adjust TCP TS ecr */
+#define FLAGS_SCTP_BAD_CRC32C     0x8  /* compute bad CRC32C for SCTP packets */
+#define FLAGS_SCTP_EXPLICIT_TAG   0x10 /* verification tag specified */
+#define FLAGS_SCTP_GENERIC_PACKET 0x20 /* set if it is a generic packet */
 
 	enum ip_ecn_t ecn;	/* IPv4/IPv6 ECN treatment for packet */
 
diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y
index 1821ff1d..bd598c0f 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -152,6 +152,12 @@ static struct script *out_script = NULL;
 /* The test invocation to pass back to parse_and_finalize_config(). */
 struct invocation *invocation;
 
+/* Temporary variables to allow passing absolute timestamp flags to
+ * the tcp_options struct from the timestamp options. Adding fields
+ * to struct tcp_option, which might be cleaner, affects the on-wire format.
+ */
+bool absolute_ts_ecr = false;
+
 /* Copy the script contents into our single linear buffer. */
 void copy_script(const char *script_buffer, struct script *script)
 {
@@ -439,6 +445,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
  */
 %union {
 	s64 integer;
+	struct abs_integer abs_integer;
 	double floating;
 	char *string;
 	char *reserved;
@@ -586,6 +593,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 %token <floating> FLOAT
 %token <integer> INTEGER HEX_INTEGER
 %token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
+%type <abs_integer> abs_integer
 %type <direction> direction
 %type <ip_ecn> opt_ip_info
 %type <ip_ecn> ip_ecn
@@ -2366,7 +2374,10 @@ tcp_packet_spec
 	inner = new_tcp_packet(in_config->wire_protocol,
 			       direction, $2, $3,
 			       $4.start_sequence, $4.payload_bytes,
-			       $5, $6, $7, &error);
+			       $5, $6, $7,
+			       absolute_ts_ecr,
+			       &error);
+	absolute_ts_ecr = false;
 	free($3);
 	free($7);
 	if (inner == NULL) {
@@ -2694,17 +2705,18 @@ tcp_option
 | SACK sack_block_list {
 	$$ = $2;
 }
-| TIMESTAMP VAL INTEGER ECR INTEGER  {
+| TIMESTAMP VAL INTEGER ECR abs_integer  {
 	u32 val, ecr;
+	absolute_ts_ecr = $5.absolute;
 	$$ = tcp_option_new(TCPOPT_TIMESTAMP, TCPOLEN_TIMESTAMP);
-	if (!is_valid_u32($3)) {
+	val = $3;
+	ecr = $5.integer;
+	if (!is_valid_u32(val)) {
 		semantic_error("ts val out of range");
 	}
-	if (!is_valid_u32($5)) {
+	if (!is_valid_u32(ecr)) {
 		semantic_error("ecr val out of range");
 	}
-	val = $3;
-	ecr = $5;
 	$$->data.time_stamp.val = htonl(val);
 	$$->data.time_stamp.ecr = htonl(ecr);
 }
@@ -2720,6 +2732,11 @@ tcp_option
 }
 ;
 
+abs_integer
+: INTEGER     { $$.integer = $1; $$.absolute = false; }
+| INTEGER '!' { $$.integer = $1; $$.absolute = true; }
+;
+
 sack_block_list
 : sack_block                 { $$ = $1; }
 | sack_block_list sack_block {
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 5a1af9a1..a1ee8b03 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -936,6 +936,10 @@ static int map_inbound_packet(
 	if (find_tcp_timestamp(live_packet, error))
 		return STATUS_ERR;
 
+	/* If we are using absolute ecr values, do not adjust the ecr. */
+	if (live_packet->flags & FLAG_ABSOLUTE_TS_ECR) {
+		return STATUS_OK;
+	}
 	/* Remap TCP timestamp echo reply from script value to a live
 	 * value. We say "a" rather than "the" live value because
 	 * there could be multiple live values corresponding to the
@@ -3389,7 +3393,7 @@ int reset_connection(struct state *state, struct socket *socket)
 
 	packet = new_tcp_packet(socket->address_family,
 				DIRECTION_INBOUND, ECN_NONE,
-				"R.", seq, 0, ack_seq, window, NULL, &error);
+				"R.", seq, 0, ack_seq, window, NULL, false, &error);
 	if (packet == NULL)
 		die("%s", error);
 
diff --git a/gtests/net/packetdrill/tcp_packet.c b/gtests/net/packetdrill/tcp_packet.c
index 03eeda1a..de415f98 100644
--- a/gtests/net/packetdrill/tcp_packet.c
+++ b/gtests/net/packetdrill/tcp_packet.c
@@ -59,6 +59,7 @@ struct packet *new_tcp_packet(int address_family,
 			       u32 ack_sequence,
 			       s32 window,
 			       const struct tcp_options *tcp_options,
+			       bool abs_ts_ecr,
 			       char **error)
 {
 	struct packet *packet = NULL;  /* the newly-allocated result packet */
@@ -157,6 +158,10 @@ struct packet *new_tcp_packet(int address_family,
 		       tcp_options->length);
 	}
 
+	if (abs_ts_ecr) {
+		packet->flags |= FLAG_ABSOLUTE_TS_ECR;
+	}
+
 	packet->ip_bytes = ip_bytes;
 	return packet;
 }
diff --git a/gtests/net/packetdrill/tcp_packet.h b/gtests/net/packetdrill/tcp_packet.h
index c5848ca2..0c065c0e 100644
--- a/gtests/net/packetdrill/tcp_packet.h
+++ b/gtests/net/packetdrill/tcp_packet.h
@@ -44,5 +44,6 @@ extern struct packet *new_tcp_packet(int address_family,
 				     u32 ack_sequence,
 				     s32 window,
 				     const struct tcp_options *tcp_options,
+				     bool abs_ts_ecr,
 				     char **error);
 #endif /* __TCP_PACKET_H__ */
diff --git a/gtests/net/packetdrill/types.h b/gtests/net/packetdrill/types.h
index a9c6055e..c6cc344d 100644
--- a/gtests/net/packetdrill/types.h
+++ b/gtests/net/packetdrill/types.h
@@ -133,6 +133,14 @@ enum ip_ecn_t {
 	ECN_NOCHECK,
 };
 
+/* Type to handle <integer>! for specifying absolute vs adjusted values.
+ * The <integer>! means absolute integer. Just a plain <integer> is relative.
+ */
+struct abs_integer {
+	s64 integer;
+	bool absolute;
+};
+
 /* Length of output buffer for inet_ntop, plus prefix length (e.g. "/128"). */
 #define ADDR_STR_LEN ((INET_ADDRSTRLEN + INET6_ADDRSTRLEN)+5)
 
-- 
GitLab