diff --git a/gtests/net/packetdrill/packet.h b/gtests/net/packetdrill/packet.h
index a51c9e1162421ed59f972a2bec91e86fdda3045c..a7510b34748cb9144996830c0660589aa9780a66 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 1821ff1dc8e23164e9f4e0ef9c15dee3424d0093..bd598c0fda356bf1456b71622041935f3cb4365d 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 5a1af9a190b941a1c99be5b0af93b706100b36a7..a1ee8b032639e594c07514199e4e6f6d5555938d 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/run_system_call.c b/gtests/net/packetdrill/run_system_call.c
index 13f0b086ea4213b023360157ef062d6d4e6ffac2..1ec42605b3162431df215656133c05f7d5ccdfad 100644
--- a/gtests/net/packetdrill/run_system_call.c
+++ b/gtests/net/packetdrill/run_system_call.c
@@ -1565,8 +1565,7 @@ static void begin_syscall(struct state *state, struct syscall_spec *syscall)
  */
 enum result_check_t {
 	CHECK_EXACT,		/* check that result matches exactly */
-	CHECK_NON_NEGATIVE,	/* check that result is non-negative */
-	CHECK_ALLOW_MAPPING,	/* checks for results after accept-syscall */
+	CHECK_FD,		/* check that result fd or matching error */
 };
 static int end_syscall(struct state *state, struct syscall_spec *syscall,
 		       enum result_check_t mode, int actual, char **error)
@@ -1587,14 +1586,14 @@ static int end_syscall(struct state *state, struct syscall_spec *syscall,
 	/* Compare actual vs expected return value */
 	if (get_s32(syscall->result, &expected, error))
 		return STATUS_ERR;
-	if (mode == CHECK_NON_NEGATIVE) {
+	if (mode == CHECK_FD && expected >= 0) {
 		if (actual < 0) {
 			asprintf(error,
 				 "Expected non-negative result but got %d with errno %d (%s)",
 				 actual, actual_errno, strerror(actual_errno));
 			return STATUS_ERR;
 		}
-	} else if (mode == CHECK_EXACT) {
+	} else if (mode == CHECK_FD || mode == CHECK_EXACT) {
 		if (actual != expected) {
 			if (actual < 0)
 				asprintf(error,
@@ -1608,18 +1607,6 @@ static int end_syscall(struct state *state, struct syscall_spec *syscall,
 					 expected, actual);
 			return STATUS_ERR;
 		}
-	} else if (mode == CHECK_ALLOW_MAPPING) {
-		if ((expected >= 0)  && (actual < 0)) {
-			asprintf(error,
-				 "Expected non-negative result but got %d with errno %d (%s)",
-				 actual, actual_errno, strerror(actual_errno));
-			return STATUS_ERR;
-		} else if ((expected < 0) && (actual != expected)) {
-			asprintf(error,
-				 "Expected result %d but got %d",
-				 expected, actual);
-			return STATUS_ERR;
-		}
 	} else {
 		assert(!"bad mode");
 	}
@@ -2005,7 +1992,7 @@ static int syscall_socket(struct state *state, struct syscall_spec *syscall,
 
 	result = socket(domain, type, protocol);
 
-	if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error))
+	if (end_syscall(state, syscall, CHECK_FD, result, error))
 		return STATUS_ERR;
 
 	if (result >= 0) {
@@ -2097,7 +2084,7 @@ static int syscall_accept(struct state *state, struct syscall_spec *syscall,
 
 	result = accept(live_fd, (struct sockaddr *)&live_addr, &live_addrlen);
 
-	if (end_syscall(state, syscall, CHECK_ALLOW_MAPPING, result, error))
+	if (end_syscall(state, syscall, CHECK_FD, result, error))
 		return STATUS_ERR;
 
 	if (result >= 0) {
@@ -4288,7 +4275,7 @@ static int syscall_open(struct state *state, struct syscall_spec *syscall,
 
 	result = open(name, flags);
 
-	if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error))
+	if (end_syscall(state, syscall, CHECK_FD, result, error))
 		return STATUS_ERR;
 
 	if (result >= 0) {
@@ -6107,14 +6094,8 @@ static int syscall_sctp_peeloff(struct state *state, struct syscall_spec *syscal
 	begin_syscall(state, syscall);
 
 	result = sctp_peeloff(live_fd, assoc_id);
-	if (result < 0) {
-		if (end_syscall(state, syscall, CHECK_EXACT, result, error))
-			return STATUS_ERR;
-		return STATUS_OK;
-	} else {
-		if (end_syscall(state, syscall, CHECK_NON_NEGATIVE, result, error))
-			return STATUS_ERR;
-	}
+	if (end_syscall(state, syscall, CHECK_FD, result, error))
+		return STATUS_ERR;
 	if (get_s32(syscall->result, &script_new_fd, error))
 		return STATUS_ERR;
 	if (run_syscall_sctp_peeloff(state, script_fd, script_new_fd, result, error)) {
@@ -6124,7 +6105,7 @@ static int syscall_sctp_peeloff(struct state *state, struct syscall_spec *syscal
 
 	return STATUS_OK;
 #else
-	asprintf(error, "sctp_connectx is not supported");
+	asprintf(error, "sctp_peeloff is not supported");
 	return STATUS_ERR;
 #endif
 }
diff --git a/gtests/net/packetdrill/tcp_packet.c b/gtests/net/packetdrill/tcp_packet.c
index 03eeda1a8496b6b5edb4c91394324879efabf8ac..de415f9811e2bafe8e7f6ac6325cb1f64145777a 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 c5848ca2f014dd7ba9e10dab89a67bc5550583b7..0c065c0e77291df076c950da2456d49486f1d6b3 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 a9c6055e2e0fb27fbcf8c864ffd3cdeff0b4fefe..c6cc344d3dee2515b64ff34a5ded8eeb7766baa6 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)