From eab89a4913ee02e5d38a35600209bdd0fa188e4c Mon Sep 17 00:00:00 2001
From: Neal Cardwell <ncardwell@google.com>
Date: Wed, 13 Nov 2013 15:30:07 -0500
Subject: [PATCH] net-test: packetdrill encap support: GRE encap parsing

Add code for basic parsing of GRE v0 headers, per RFC 1701.


Change-Id: I0d564f3ef17132f94a1df76512409b4cee7b441f
---
 gtests/net/packetdrill/packet_parser.c | 55 ++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/gtests/net/packetdrill/packet_parser.c b/gtests/net/packetdrill/packet_parser.c
index 02b7ae33..6001c800 100644
--- a/gtests/net/packetdrill/packet_parser.c
+++ b/gtests/net/packetdrill/packet_parser.c
@@ -432,6 +432,57 @@ error_out:
 	return PACKET_BAD;
 }
 
+/* Parse the GRE header. Return a packet_parse_result_t. */
+static int parse_gre(struct packet *packet, u8 *layer4_start, int layer4_bytes,
+		     u8 *packet_end, char **error)
+{
+	struct header *gre_header = NULL;
+	u8 *p = layer4_start;
+	struct gre *gre = (struct gre *) p;
+
+	assert(layer4_bytes >= 0);
+	if (layer4_bytes < sizeof(struct gre)) {
+		asprintf(error, "Truncated GRE header");
+		goto error_out;
+	}
+	if (gre->version != 0) {
+		asprintf(error, "GRE header has unsupported version number");
+		goto error_out;
+	}
+	if (gre->has_routing) {
+		asprintf(error, "GRE header has unsupported routing info");
+		goto error_out;
+	}
+	const int gre_header_len = gre_len(gre);
+	if (gre_header_len < sizeof(struct gre)) {
+		asprintf(error, "GRE header length too small for GRE header");
+		goto error_out;
+	}
+	if (gre_header_len > layer4_bytes) {
+		asprintf(error, "GRE header length too big");
+		goto error_out;
+	}
+
+	assert(p + layer4_bytes <= packet_end);
+
+	DEBUGP("GRE header len: %d\n", gre_header_len);
+
+	gre_header = packet_append_header(packet, HEADER_GRE, gre_header_len);
+	if (gre_header == NULL) {
+		asprintf(error, "Too many nested headers at GRE header");
+		goto error_out;
+	}
+	gre_header->total_bytes = layer4_bytes;
+
+	p += gre_header_len;
+	assert(p <= packet_end);
+	return parse_layer3_packet_by_proto(packet, ntohs(gre->protocol),
+					    p, packet_end, error);
+
+error_out:
+	return PACKET_BAD;
+}
+
 static int parse_layer4(struct packet *packet, u8 *layer4_start,
 			int layer4_protocol, int layer4_bytes,
 			u8 *packet_end, bool *is_inner, char **error)
@@ -444,6 +495,10 @@ static int parse_layer4(struct packet *packet, u8 *layer4_start,
 		*is_inner = true;	/* found inner-most layer 4 */
 		return parse_udp(packet, layer4_start, layer4_bytes, packet_end,
 				 error);
+	} else if (layer4_protocol == IPPROTO_GRE) {
+		*is_inner = false;
+		return parse_gre(packet, layer4_start, layer4_bytes, packet_end,
+				 error);
 	} else if (layer4_protocol == IPPROTO_IPIP) {
 		*is_inner = false;
 		return parse_ipv4(packet, layer4_start, packet_end, error);
-- 
GitLab