From d62b288697683b40cffed37fbc9761383be17e0c Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
Date: Thu, 6 Jul 2017 08:53:14 +0200
Subject: [PATCH] Add support for absolute TCP sequence numbers.

Sponsored by:	Netflix, Inc.
---
 gtests/net/packetdrill/packet.h     |  9 +++++----
 gtests/net/packetdrill/parser.y     | 23 ++++++++++++++++++++++-
 gtests/net/packetdrill/run_packet.c | 17 +++++++++++------
 gtests/net/packetdrill/tcp_packet.c |  4 ++++
 gtests/net/packetdrill/tcp_packet.h |  1 +
 5 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/gtests/net/packetdrill/packet.h b/gtests/net/packetdrill/packet.h
index fa7416c2..3d7de771 100644
--- a/gtests/net/packetdrill/packet.h
+++ b/gtests/net/packetdrill/packet.h
@@ -109,10 +109,11 @@ struct packet {
 #define FLAG_WIN_NOCHECK          0x1  /* don't check TCP receive window */
 #define FLAG_OPTIONS_NOCHECK      0x2  /* don't check TCP options */
 #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 */
-#define FLAGS_UDP_ENCAPSULATED    0x40 /* TCP/UDP or SCTP/UDP encapsulated */
+#define FLAG_ABSOLUTE_SEQ         0x8  /* don't adjust TCP.SEQ */
+#define FLAGS_SCTP_BAD_CRC32C     0x10 /* compute bad CRC32C for SCTP packets */
+#define FLAGS_SCTP_EXPLICIT_TAG   0x20 /* verification tag specified */
+#define FLAGS_SCTP_GENERIC_PACKET 0x40 /* set if it is a generic packet */
+#define FLAGS_UDP_ENCAPSULATED    0x80 /* TCP/UDP or SCTP/UDP encapsulated */
 
 	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 399656cd..715bfd2b 100644
--- a/gtests/net/packetdrill/parser.y
+++ b/gtests/net/packetdrill/parser.y
@@ -460,6 +460,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
 	struct {
 		u32 start_sequence;
 		u16 payload_bytes;
+		bool absolute;
 	} tcp_sequence_info;
 	struct {
 		int protocol;
@@ -2319,7 +2320,7 @@ sctp_protocol_violation_cause_spec
 }
 
 tcp_packet_spec
-: packet_prefix opt_ip_info flags seq opt_ack opt_window opt_tcp_options opt_udp_encaps_info{
+: packet_prefix opt_ip_info flags seq opt_ack opt_window opt_tcp_options opt_udp_encaps_info {
 	char *error = NULL;
 	struct packet *outer = $1, *inner = NULL;
 	enum direction_t direction = outer->direction;
@@ -2335,6 +2336,7 @@ tcp_packet_spec
 			       $4.start_sequence, $4.payload_bytes,
 			       $5, $6, $7,
 			       absolute_ts_ecr,
+			       $4.absolute,
 			       $8.udp_src_port, $8.udp_dst_port,
 			       &error);
 	absolute_ts_ecr = false;
@@ -2598,6 +2600,25 @@ seq
 	}
 	$$.start_sequence = $1;
 	$$.payload_bytes = $5;
+	$$.absolute = false;
+}
+| INTEGER ':' INTEGER '(' INTEGER ')' '!' {
+	if (!is_valid_u32($1)) {
+		semantic_error("TCP start sequence number out of range");
+	}
+	if (!is_valid_u32($3)) {
+		semantic_error("TCP end sequence number out of range");
+	}
+	if (!is_valid_u16($5)) {
+		semantic_error("TCP payload size out of range");
+	}
+	if ($3 != ($1 +$5)) {
+		semantic_error("inconsistent TCP sequence numbers and "
+			       "payload size");
+	}
+	$$.start_sequence = $1;
+	$$.payload_bytes = $5;
+	$$.absolute = true;
 }
 ;
 
diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c
index 350bbe4a..3debc5d7 100644
--- a/gtests/net/packetdrill/run_packet.c
+++ b/gtests/net/packetdrill/run_packet.c
@@ -940,8 +940,10 @@ static int map_inbound_packet(
 	/* Remap the sequence number from script sequence number to live. */
 	const bool is_syn = live_packet->tcp->syn;
 	const u32 seq_offset = remote_seq_script_to_live_offset(socket, is_syn);
-	live_packet->tcp->seq =
-	    htonl(ntohl(live_packet->tcp->seq) + seq_offset);
+	if ((live_packet->flags & FLAG_ABSOLUTE_SEQ) == 0) {
+		live_packet->tcp->seq =
+		    htonl(ntohl(live_packet->tcp->seq) + seq_offset);
+	}
 
 	/* Remap the ACK and SACKs from script sequence number to live. */
 	const u32 ack_offset = local_seq_script_to_live_offset(socket, is_syn);
@@ -1188,9 +1190,12 @@ static int map_outbound_live_packet(
 	/* Rewrite TCP sequence number from live to script space. */
 	const bool is_syn = live_packet->tcp->syn;
 	const u32 seq_offset = local_seq_live_to_script_offset(socket, is_syn);
-	actual_packet->tcp->seq =
-	    htonl(ntohl(live_packet->tcp->seq) + seq_offset);
-
+	if ((script_packet->flags & FLAG_ABSOLUTE_SEQ) == 0) {
+		actual_packet->tcp->seq =
+		    htonl(ntohl(live_packet->tcp->seq) + seq_offset);
+	} else {
+		actual_packet->tcp->seq = live_packet->tcp->seq;
+	}
 	/* Rewrite ACKs and SACKs from live to script space. */
 	const u32 ack_offset = remote_seq_live_to_script_offset(socket, is_syn);
 	if (actual_packet->tcp->ack)
@@ -3522,7 +3527,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, false,
-				udp_src_port, udp_dst_port, &error);
+				false, udp_src_port, udp_dst_port, &error);
 	if (packet == NULL)
 		die("%s", error);
 
diff --git a/gtests/net/packetdrill/tcp_packet.c b/gtests/net/packetdrill/tcp_packet.c
index e83a8066..2bbe13f8 100644
--- a/gtests/net/packetdrill/tcp_packet.c
+++ b/gtests/net/packetdrill/tcp_packet.c
@@ -60,6 +60,7 @@ struct packet *new_tcp_packet(int address_family,
 			       s32 window,
 			       const struct tcp_options *tcp_options,
 			       bool abs_ts_ecr,
+			       bool abs_seq,
 			       u16 udp_src_port,
 			       u16 udp_dst_port,
 			       char **error)
@@ -183,6 +184,9 @@ struct packet *new_tcp_packet(int address_family,
 	if (abs_ts_ecr) {
 		packet->flags |= FLAG_ABSOLUTE_TS_ECR;
 	}
+	if (abs_seq) {
+		packet->flags |= FLAG_ABSOLUTE_SEQ;
+	}
 
 	packet->ip_bytes = ip_bytes;
 	return packet;
diff --git a/gtests/net/packetdrill/tcp_packet.h b/gtests/net/packetdrill/tcp_packet.h
index 415445e9..deacd96f 100644
--- a/gtests/net/packetdrill/tcp_packet.h
+++ b/gtests/net/packetdrill/tcp_packet.h
@@ -45,6 +45,7 @@ extern struct packet *new_tcp_packet(int address_family,
 				     s32 window,
 				     const struct tcp_options *tcp_options,
 				     bool abs_ts_ecr,
+				     bool abs_seq,
 				     u16 udp_src_port,
 				     u16 udp_dst_port,
 				     char **error);
-- 
GitLab