diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l
index 097cdc9e1fad2ecca067097b58813f9cf022af6b..1244636e640f55631833deeaf5e96884b3785888 100644
--- a/gtests/net/packetdrill/lexer.l
+++ b/gtests/net/packetdrill/lexer.l
@@ -103,6 +103,95 @@ static s64 hextol(const char *s)
 	return strtol(yytext + 2, NULL, 16);
 }
 
+enum ifdef_os {
+	Linux_IFDEF = 1, FreeBSD_IFDEF, NetBSD_IFDEF, OpenBSD_IFDEF
+};
+
+#define MAX_IFDEF_DEPTH 1
+YY_BUFFER_STATE ifdef_stack[MAX_IFDEF_DEPTH];
+int ifdef_stack_ptr = 0;
+
+static inline int get_os_name_length(enum ifdef_os os) {
+	switch (os) {
+	case Linux_IFDEF:
+		return strlen("Linux");
+	case FreeBSD_IFDEF:
+		return strlen("FreeBSD");
+	case NetBSD_IFDEF:
+		return strlen("NetBSD");
+	case OpenBSD_IFDEF:
+		return strlen("OpenBSD");
+	default:
+		return -1;
+	}
+}
+
+static inline bool ignore_ifdef(enum ifdef_os os) {
+#ifdef linux
+	if (os == Linux_IFDEF) {
+		return false;
+	}
+#endif
+#ifdef __FreeBSD__
+	if (os == FreeBSD_IFDEF) {
+		return false;
+	}
+#endif
+#ifdef __OpenBSD__
+	if (os == OpenBSD_IFDEF) {
+		return false;
+	}
+#endif
+#ifdef __NetBSD__
+	if (os == NetBSD_IFDEF) {
+		return false;
+	}
+#endif
+	
+	return true;
+}
+
+static inline char* remove_ifdef_start_and_endtag(char *code, int os_name_length) {
+	unsigned int ifdef_length = strlen("#ifdef ");
+	unsigned int endif_length = strlen("#endif");
+	unsigned int newline_before_endif = 0;
+	char *code_without_ifdef = NULL;
+	
+	code_without_ifdef = code + ifdef_length + os_name_length;
+	newline_before_endif = strlen(code_without_ifdef) - endif_length;
+	code_without_ifdef[newline_before_endif] = (char) 0;
+	return code_without_ifdef;
+}
+	
+
+static void handle_ifdef(enum ifdef_os os, const char *s) {
+	char *code = NULL;
+	char *code_without_ifdef = NULL;
+	int os_name_length = get_os_name_length(os);
+	
+	if (os_name_length == -1) {
+		fprintf(stderr, "handle_ifdef with unknown os called.\n");
+		exit(1);
+	}
+	
+	if (ignore_ifdef(os)) {
+		return;
+	}
+	
+	if (ifdef_stack_ptr >= MAX_IFDEF_DEPTH) {
+		fprintf(stderr, "Ifdefs nested too deeply");
+		exit(1);
+	}
+	
+	code = strdup(s);
+	
+	code_without_ifdef = remove_ifdef_start_and_endtag(code, os_name_length);
+	ifdef_stack[ifdef_stack_ptr++] = YY_CURRENT_BUFFER;
+	yy_switch_to_buffer(yy_scan_string(code_without_ifdef));
+	
+	free(code);
+}
+
 %}
 
 %{
@@ -122,6 +211,29 @@ cpp_comment	\/\/[^\n]*\n
  */
 c_comment	\/\*(([^*])|(\*[^\/]))*\*\/
 
+/* This matches the following platform specific #ifdef-forms:
+ *   #ifdef Linux   => Code that only Linux hosts should execute
+ *   #ifdef FreeBSD => Code that only FreeBSD hosts should execute
+ *   #ifdef OpenBSD => Code that only OpenBSD hosts should execute
+ *   #ifdef NetBSD  => Code that only NetBSD hosts should execute
+ *   
+ *   the pattern for using #ifdef is like this:
+ *   #ifdef Linux
+ *   (specific code only for linux)
+ *   #endif
+ */
+
+/* these are the tags that identify the start and ending of an ifdef block */
+ifdef_begin #ifdef[ ]
+ifdef_end   #endif
+/* end_matcher actually matches everything except the "#endif" tag. */
+end_matcher (([^#])|(#[^e])|(#e[^n])|(#en[^d])|(#end[^i])|(#endi[^f]))*
+
+ifdef_freebsd	{ifdef_begin}(?i:FreeBSD){end_matcher}{ifdef_end}
+ifdef_linux		{ifdef_begin}(?i:Linux){end_matcher}{ifdef_end}
+ifdef_openbsd	{ifdef_begin}(?i:OpenBSD){end_matcher}{ifdef_end}
+ifdef_netbsd	{ifdef_begin}(?i:NetBSD){end_matcher}{ifdef_end}
+
 /* The regexp for code snippets is analogous to that for C comments.
  * Here is a summary of the regexp for code snippets:
  *   %{
@@ -480,7 +592,19 @@ NULL				return NULL_;
 [ \t\n]+			/* ignore whitespace */;
 {cpp_comment}			/* ignore C++-style comment */;
 {c_comment}			/* ignore C-style comment */;
+{ifdef_freebsd}			handle_ifdef(FreeBSD_IFDEF, yytext);
+{ifdef_linux}			handle_ifdef(Linux_IFDEF, yytext);
+{ifdef_openbsd}			handle_ifdef(OpenBSD_IFDEF, yytext);
+{ifdef_netbsd}			handle_ifdef(NetBSD_IFDEF, yytext);
 {code}				yylval.string = code(yytext);   return CODE;
 {ipv4_addr}			yylval.string = strdup(yytext); return IPV4_ADDR;
 {ipv6_addr}			yylval.string = strdup(yytext); return IPV6_ADDR;
+<<EOF>>				{
+					if ( --ifdef_stack_ptr < 0 ) {
+						yyterminate();
+					} else {
+						yy_delete_buffer(YY_CURRENT_BUFFER);
+						yy_switch_to_buffer(ifdef_stack[ifdef_stack_ptr]);
+					}
+				}
 %%
diff --git a/gtests/net/packetdrill/tests/bsd/sctp/ifdef_testcase.pkt b/gtests/net/packetdrill/tests/bsd/sctp/ifdef_testcase.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..996106632f3f299ddc206100e0873181ac76cbb9
--- /dev/null
+++ b/gtests/net/packetdrill/tests/bsd/sctp/ifdef_testcase.pkt
@@ -0,0 +1,26 @@
+// Create a non-blocking 1-to-1 style socket
+ 0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
++0.0 bind(3, ..., ...) = 0
++0.0 fcntl(3, F_GETFL) = 0x02 (flags O_RDWR)
++0.0 fcntl(3, F_SETFL, O_RDWR | O_NONBLOCK) = 0
+// Trigger the active associtation setup
++0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
++0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...]
++0.0 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=1500, os=1, is=1, tsn=1, STATE_COOKIE[len=4, val=...]]
++0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
++0.0 < sctp: COOKIE_ACK[flgs=0]
+// Check if the setup was sucessful
++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
+// inject sack-chunk(type=3) with invalid len=8| cumulative tsn ack  |
++0.0 < sctp: CHUNK[type=3, flgs=0, len=8, val=[0x00, 0x00, 0x00, 0x01]]
+#ifdef Linux
+// expect protocol violation
++0.0 > sctp: ABORT[flgs=..., PROTOCOL_VIOLATION[info=...]]
+#endif
+#ifdef FreeBSD
++0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
++0.0 close(3) = 0
++0.0 > sctp: SHUTDOWN[flgs=0, cum_tsn=0]
++0.1 < sctp: SHUTDOWN_ACK[flgs=0]
++0.0 > sctp: SHUTDOWN_COMPLETE[flgs=0]
+#endif