Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
%{
/*
* Copyright 2013 Google Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/*
* Author: Author: ncardwell@google.com (Neal Cardwell)
*
* This is the parser for the packetdrill script language. It is
* processed by the bison parser generator.
*
* For full documentation see: http://www.gnu.org/software/bison/manual/
*
* Here is a quick and dirty tutorial on bison:
*
* A bison parser specification is basically a BNF grammar for the
* language you are parsing. Each rule specifies a nonterminal symbol
* on the left-hand side and a sequence of terminal symbols (lexical
* tokens) and or nonterminal symbols on the right-hand side that can
* "reduce" to the symbol on the left hand side. When the parser sees
* the sequence of symbols on the right where it "wants" to see a
* nonterminal on the left, the rule fires, executing the semantic
* action code in curly {} braces as it reduces the right hand side to
* the left hand side.
*
* The semantic action code for a rule produces an output, which it
* can reference using the $$ token. The set of possible types
* returned in output expressions is given in the %union section of
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
* the .y file. The specific type of the output for a terminal or
* nonterminal symbol (corresponding to a field in the %union) is
* given by the %type directive in the .y file. The action code can
* access the outputs of the symbols on the right hand side by using
* the notation $1 for the first symbol, $2 for the second symbol, and
* so on.
*
* The lexer (generated by flex from lexer.l) feeds a stream of
* terminal symbols up to this parser. Parser semantic actions can
* access the lexer output for a terminal symbol with the same
* notation they use for nonterminals.
*
* Here's an example rule with its semantic action in {} braces:
*
* tcp_option
* ...
* | MSS INTEGER {
* $$ = tcp_option_new(...);
* ...
* $$->data.mss.bytes = htons($2);
* }
*
* This rule basically says:
*
* When the parser wants to see a tcp_option, if it sees an MSS from
* the lexer followed by an INTEGER from the lexer then run the
* action code that (a) stores in the output $$ a pointer to a
* struct tcp_option object, and then (b) stores in that object the
* value of the INTEGER token (accessed with $2).
*
*/
/* The first part of the .y file consists of C code that bison copies
* directly into the top of the .c file it generates.
*/
#include "types.h"
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "gre_packet.h"
#include "ip_packet.h"
#include "icmp_packet.h"
#include "logging.h"
#include "mpls.h"
#include "mpls_packet.h"
#include "tcp_packet.h"
#include "udp_packet.h"
#include "parse.h"
#include "script.h"
#include "tcp.h"
#include "tcp_options.h"
/* This include of the bison-generated .h file must go last so that we
* can first include all of the declarations on which it depends.
*/
#include "parser.h"
/* Change this YYDEBUG to 1 to get verbose debug output for parsing: */
#define YYDEBUG 0
#if YYDEBUG
extern int yydebug;
#endif
extern FILE *yyin;
extern int yylineno;
extern char *yytext;
extern int yylex(void);
extern int yyparse(void);
extern int yywrap(void);
/* This mutex guards all parser global variables declared in this file. */
pthread_mutex_t parser_mutex = PTHREAD_MUTEX_INITIALIZER;
/* The input to the parser: the path name of the script file to parse. */
const char* current_script_path = NULL;
/* The starting line number of the input script statement that we're
* currently parsing. This may be different than yylineno if bison had
* to look ahead and lexically scan a token on the following line to
* decide that the current statement is done.
*/
static int current_script_line = -1;
/*
* We uses this object to look up configuration info needed during
* parsing (such as whether packets are IPv4 or IPv6).
*/
struct config *in_config = NULL;
/* The output of the parser: an output script containing
* 1) a linked list of options
* 2) a linked list of events
*/
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 or ignore 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 ignore_ts_val = false;
bool absolute_ts_ecr = false;
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* Copy the script contents into our single linear buffer. */
void copy_script(const char *script_buffer, struct script *script)
{
DEBUGP("copy_script\n");
free(script->buffer);
script->length = strlen(script_buffer);
script->buffer = strdup(script_buffer);
assert(script->buffer != NULL);
DEBUGP("copy_script: %d bytes\n", script->length);
}
/* Read the script file into a single linear buffer. */
void read_script(const char *script_path, struct script *script)
{
int size = 0;
DEBUGP("read_script(%s)\n", script_path);
while (script->buffer == NULL) {
struct stat script_info;
int fd = -1;
/* Allocate a buffer big enough for the whole file. */
if (stat(script_path, &script_info) != 0)
Barath Raghavan
committed
die("parse error: stat() of script file '%s': %s\n",
script_path, strerror(errno));
/* Pick a buffer size larger than the file, so we'll
* know if the file grew.
*/
size = max((int)script_info.st_size, size) + 1;
script->buffer = malloc(size);
assert(script->buffer != NULL);
/* Read the file into our buffer. */
fd = open(script_path, O_RDONLY);
if (fd < 0)
Barath Raghavan
committed
die("parse error opening script file '%s': %s\n",
script_path, strerror(errno));
script->length = read(fd, script->buffer, size);
if (script->length < 0)
Barath Raghavan
committed
die("parse error reading script file '%s': %s\n",
script_path, strerror(errno));
/* If we filled the buffer, then probably another
* process wrote more to the file since our stat call,
* so we should try again.
*/
if (script->length == size) {
free(script->buffer);
script->buffer = NULL;
script->length = 0;
}
if (close(fd))
die_perror("close");
}
DEBUGP("read_script: %d bytes\n", script->length);
}
/* The public entry point for the script parser. Parses the
* text script file with the given path name and fills in the script
* object with the parsed representation.
*/
int parse_script(struct config *config,
struct script *script,
struct invocation *callback_invocation)
{
/* This bison-generated parser is not multi-thread safe, so we
* have a lock to prevent more than one thread using the
* parser at the same time. This is useful in the wire server
* context, where in general we may have more than one test
* thread running at the same time.
*/
if (pthread_mutex_lock(&parser_mutex) != 0)
die_perror("pthread_mutex_lock");
#if YYDEBUG
yydebug = 1;
#endif
/* Now parse the script from our buffer. */
yyin = fmemopen(script->buffer, script->length, "r");
if (yyin == NULL)
Barath Raghavan
committed
die_perror("fmemopen: parse error opening script buffer");
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
current_script_path = config->script_path;
in_config = config;
out_script = script;
invocation = callback_invocation;
/* We have to reset the line number here since the wire server
* can do more than one yyparse().
*/
yylineno = 1;
int result = yyparse(); /* invoke bison-generated parser */
current_script_path = NULL;
if (fclose(yyin))
die_perror("fclose: error closing script buffer");
/* Unlock parser. */
if (pthread_mutex_unlock(&parser_mutex) != 0)
die_perror("pthread_mutex_unlock");
return result ? STATUS_ERR : STATUS_OK;
}
/* Bison emits code to call this method when there's a parse-time error.
* We print the line number and the error message.
*/
static void yyerror(const char *message)
{
fprintf(stderr, "%s:%d: parse error at '%s': %s\n",
current_script_path, yylineno, yytext, message);
}
/* After we finish parsing each line of a script, we analyze the
* semantics of the line. If we encounter an error then we print the
* error message to stderr and exit with an error.
*/
static void semantic_error(const char* message)
{
assert(current_script_line >= 0);
Barath Raghavan
committed
die("%s:%d: semantic error: %s\n",
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
current_script_path, current_script_line, message);
}
/* This standard callback is invoked by flex when it encounters
* the end of a file. We return 1 to tell flex to return EOF.
*/
int yywrap(void)
{
return 1;
}
/* Create and initalize a new expression. */
static struct expression *new_expression(enum expression_t type)
{
struct expression *expression = calloc(1, sizeof(struct expression));
expression->type = type;
return expression;
}
/* Create and initalize a new integer expression with the given
* literal value and format string.
*/
static struct expression *new_integer_expression(s64 num, const char *format)
{
struct expression *expression = new_expression(EXPR_INTEGER);
expression->value.num = num;
expression->format = format;
return expression;
}
/* Create and initalize a new one-element expression_list. */
static struct expression_list *new_expression_list(
struct expression *expression)
{
struct expression_list *list;
list = calloc(1, sizeof(struct expression_list));
list->expression = expression;
list->next = NULL;
return list;
}
/* Add the expression to the end of the list. */
static void expression_list_append(struct expression_list *list,
struct expression *expression)
{
while (list->next != NULL) {
list = list->next;
}
list->next = new_expression_list(expression);
}
/* Create and initialize a new option. */
static struct option_list *new_option(char *name, char *value)
{
struct option_list *opt = calloc(1, sizeof(struct option_list));
opt->name = name;
opt->value = value;
return opt;
}
/* Create and initialize a new event. */
static struct event *new_event(enum event_t type)
{
struct event *e = calloc(1, sizeof(struct event));
e->type = type;
e->time_usecs_end = NO_TIME_RANGE;
e->offset_usecs = NO_TIME_RANGE;
return e;
}
static int parse_hex_byte(const char *hex, u8 *byte)
{
if (!isxdigit((int)hex[0]) || !isxdigit((int)hex[1])) {
return STATUS_ERR; /* need two hex digits per byte */
}
char buf[] = { hex[0], hex[1], '\0' };
char* buf_end = NULL;
u32 byte_value = strtoul(buf, &buf_end, 16);
assert(byte_value <= 0xff);
assert(buf_end == buf + 2);
*byte = byte_value;
return STATUS_OK;
}
/* Converts a hex string in 'hex' into bytes and stores them in a
* buffer 'buf' of length 'buf_len' bytes; returns number of bytes in
* out_len. Works for hex strings of arbitrary size, such as very long
* TCP Fast Open cookies.
*/
static int parse_hex_string(const char *hex, u8 *buf, int buf_len,
int *out_len)
{
u8 *out = buf;
u8 *buf_end = buf + buf_len;
while (hex[0] != '\0') {
if (out >= buf_end) {
return STATUS_ERR; /* ran out of output space */
}
if (parse_hex_byte(hex, out))
return STATUS_ERR; /* bad character */
hex += 2;
out += 1;
}
*out_len = out - buf;
assert(*out_len <= buf_len);
return STATUS_OK;
}
static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string,
{
int cookie_string_len = strlen(cookie_string);
if (cookie_string_len & 1) {
asprintf(error,
"TCP fast open cookie has an odd number of digits");
return NULL;
}
int cookie_bytes = cookie_string_len / 2; /* 2 hex chars per byte */
if (cookie_bytes > MAX_TCP_FAST_OPEN_COOKIE_BYTES) {
asprintf(error, "TCP fast open cookie too long");
asprintf(error, "TCP fast open cookie of %d bytes "
"exceeds maximum cookie length of %d bytes",
cookie_bytes, MAX_TCP_FAST_OPEN_COOKIE_BYTES);
return NULL;
}
u8 option_bytes = TCPOLEN_FASTOPEN_BASE + cookie_bytes;
option = tcp_option_new(TCPOPT_FASTOPEN, option_bytes);
int parsed_bytes = 0;
/* Parse cookie. This should be an ASCII hex string
* representing an even number of bytes (4-16 bytes). But we
* do not enforce this, since we want to allow test cases that
* supply invalid cookies.
*/
if (parse_hex_string(cookie_string, option->data.fast_open.cookie,
sizeof(option->data.fast_open.cookie),
&parsed_bytes)) {
free(option);
asprintf(error,
"TCP fast open cookie is not a valid hex string");
return NULL;
}
assert(parsed_bytes == cookie_bytes);
return option;
}
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
static struct tcp_option *new_tcp_exp_fast_open_option(const char *cookie_string,
char **error)
{
int cookie_string_len = strlen(cookie_string);
if (cookie_string_len & 1) {
asprintf(error,
"TCP fast open cookie has an odd number of digits");
return NULL;
}
int cookie_bytes = cookie_string_len / 2; /* 2 hex chars per byte */
if (cookie_bytes > MAX_TCP_EXP_FAST_OPEN_COOKIE_BYTES) {
asprintf(error, "TCP fast open cookie too long");
asprintf(error, "TCP fast open cookie of %d bytes "
"exceeds maximum cookie length of %d bytes",
cookie_bytes, MAX_TCP_EXP_FAST_OPEN_COOKIE_BYTES);
return NULL;
}
u8 option_bytes = TCPOLEN_EXP_FASTOPEN_BASE + cookie_bytes;
struct tcp_option *option;
option = tcp_option_new(TCPOPT_EXP, option_bytes);
option->data.exp_fast_open.magic = htons(TCPOPT_FASTOPEN_MAGIC);
int parsed_bytes = 0;
/* Parse cookie. This should be an ASCII hex string
* representing an even number of bytes (4-16 bytes). But we
* do not enforce this, since we want to allow test cases that
* supply invalid cookies.
*/
if (parse_hex_string(cookie_string, option->data.exp_fast_open.cookie,
sizeof(option->data.exp_fast_open.cookie),
&parsed_bytes)) {
free(option);
asprintf(error,
"TCP fast open cookie is not a valid hex string");
return NULL;
}
assert(parsed_bytes == cookie_bytes);
return option;
}
%}
%locations
%expect 1 /* we expect a shift/reduce conflict for the | binary expression */
/* The %union section specifies the set of possible types for values
* for all nonterminal and terminal symbols in the grammar.
*/
%union {
s64 integer;
struct ignore_integer ignore_integer;
double floating;
char *string;
char *reserved;
s64 time_usecs;
enum direction_t direction;
enum ip_ecn_t ip_ecn;
struct mpls_stack *mpls_stack;
struct mpls mpls_stack_entry;
u16 port;
s32 window;
u32 sequence_number;
struct {
u32 start_sequence;
u16 payload_bytes;
bool ignore;
struct {
int protocol;
u16 payload_bytes;
u32 verification_tag; /* used for SCTP */
u32 start_sequence; /* used for TCP */
u16 checksum_coverage; /* used for UDPLite */
u16 udp_src_port;
u16 udp_dst_port;
struct {
u16 udp_src_port;
u16 udp_dst_port;
} udp_encaps_info;
struct {
bool bad_crc32c;
s64 tag;
} sctp_header_spec;
struct option_list *option;
struct event *event;
struct packet *packet;
struct sctp_chunk_list_item *chunk_list_item;
struct sctp_chunk_list *chunk_list;
struct sctp_byte_list_item *byte_list_item;
struct sctp_byte_list *byte_list;
struct sctp_u16_list *u16_list;
struct sctp_u16_list_item *u16_item;
struct sctp_sack_block_list_item *sack_block_list_item;
struct sctp_sack_block_list *sack_block_list;
struct sctp_forward_tsn_ids_list *forward_tsn_ids_list;
struct sctp_forward_tsn_ids_list_item *forward_tsn_ids_list_item;
struct sctp_i_forward_tsn_ids_list *i_forward_tsn_ids_list;
struct sctp_i_forward_tsn_ids_list_item *i_forward_tsn_ids_list_item;
struct sctp_address_type_list_item *address_type_list_item;
struct sctp_address_type_list *address_type_list;
struct sctp_parameter_type_list_item *parameter_type_list_item;
struct sctp_parameter_type_list *parameter_type_list;
struct sctp_parameter_list_item *parameter_list_item;
struct sctp_parameter_list *parameter_list;
struct sctp_cause_list_item *cause_list_item;
struct sctp_cause_list *cause_list;
struct syscall_spec *syscall;
struct command_spec *command;
struct code_spec *code;
struct tcp_option *tcp_option;
struct tcp_options *tcp_options;
struct expression *expression;
struct expression_list *expression_list;
struct errno_spec *errno_info;
}
/* The specific type of the output for a symbol is given by the %type
* directive. By convention terminal symbols returned from the lexer
* have ALL_CAPS names, and nonterminal symbols have lower_case names.
*/
%token ELLIPSIS
%token <reserved> SA_FAMILY SIN_PORT SIN_ADDR _HTONS_ _HTONL_ INET_ADDR
%token <reserved> MSG_NAME MSG_IOV MSG_FLAGS MSG_CONTROL _CMSG_LEN_ CMSG_LEVEL CMSG_TYPE _CMSG_DATA_
%token <reserved> SF_HDTR_HEADERS SF_HDTR_TRAILERS
%token <reserved> FD EVENTS REVENTS ONOFF LINGER
%token <reserved> ACK ECR EOL MSS NOP SACK NR_SACK SACKOK TIMESTAMP VAL WIN WSCALE PRO
%token <reserved> EXP_FAST_OPEN FAST_OPEN
%token <reserved> IPV4 IPV6 ICMP SCTP UDP UDPLITE GRE MTU
%token <reserved> MPLS LABEL TC TTL
%token <reserved> FUNCTION_SET_NAME PCBCNT
%token <reserved> SRTO_ASSOC_ID SRTO_INITIAL SRTO_MAX SRTO_MIN
%token <reserved> SINIT_NUM_OSTREAMS SINIT_MAX_INSTREAMS SINIT_MAX_ATTEMPTS
%token <reserved> SINIT_MAX_INIT_TIMEO
%token <reserved> ASSOC_ID ASSOC_VALUE SHMAC_NUMBER_OF_IDENTS SHMAC_IDENTS
%token <reserved> STREAM_ID STREAM_VALUE
%token <reserved> SCACT_ASSOC_ID SCACT_KEYNUMBER SACK_ASSOC_ID SACK_DELAY SACK_FREQ
%token <reserved> SSTAT_ASSOC_ID SSTAT_STATE SSTAT_RWND SSTAT_UNACKDATA SSTAT_PENDDATA
%token <reserved> SSTAT_INSTRMS SSTAT_OUTSTRMS SSTAT_FRAGMENTATION_POINT
%token <reserved> SSTAT_PRIMARY
%token <reserved> SPINFO_ASSOC_ID SPINFO_ADDRESS SPINFO_STATE SPINFO_CWND SPINFO_SRTT SPINFO_RTO
hoelscher
committed
%token <reserved> SPINFO_MTU GAUTH_ASSOC_ID GAUTH_NUMBER_OF_CHUNKS GAUTH_CHUNKS
%token <reserved> CHUNK DATA INIT INIT_ACK HEARTBEAT HEARTBEAT_ACK ABORT
%token <reserved> SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECNE CWR
%token <reserved> SHUTDOWN_COMPLETE I_DATA PAD RECONFIG FORWARD_TSN I_FORWARD_TSN
%token <reserved> AUTH ASCONF ASCONF_ACK
%token <reserved> TAG A_RWND OS IS TSN SID SSN MID PPID FSN CUM_TSN GAPS NR_GAPS DUPS
%token <reserved> PARAMETER HEARTBEAT_INFORMATION IPV4_ADDRESS IPV6_ADDRESS
%token <reserved> STATE_COOKIE UNRECOGNIZED_PARAMETER COOKIE_PRESERVATIVE
Aomx
committed
%token <reserved> HOSTNAME_ADDRESS SUPPORTED_ADDRESS_TYPES ECN_CAPABLE FORWARD_TSN_SUPPORTED
%token <reserved> SUPPORTED_EXTENSIONS ADAPTATION_CODE_POINT ADAPTATION_INDICATION
%token <reserved> OUTGOING_SSN_RESET REQ_SN RESP_SN LAST_TSN IDS SIDS INCOMING_SSN_RESET
%token <reserved> RECONFIG_RESPONSE RESULT SENDER_NEXT_TSN RECEIVER_NEXT_TSN
%token <reserved> SSN_TSN_RESET ADD_INCOMING_STREAMS NUMBER_OF_NEW_STREAMS
%token <reserved> ADD_OUTGOING_STREAMS RECONFIG_REQUEST_GENERIC
%token <reserved> ADDR INCR TYPES PARAMS
%token <reserved> IPV4_TYPE IPV6_TYPE HOSTNAME_TYPE
%token <reserved> CAUSE
%token <reserved> CAUSE_CODE CAUSE_INFO
%token <reserved> INVALID_STREAM_IDENTIFIER MISSING_MANDATORY_PARAMETER
%token <reserved> STALE_COOKIE_ERROR OUT_OF_RESOURCE
%token <reserved> UNRESOLVABLE_ADDRESS UNRECOGNIZED_CHUNK_TYPE
%token <reserved> INVALID_MANDATORY_PARAMETER NO_USER_DATA
%token <reserved> COOKIE_RECEIVED_WHILE_SHUTDOWN RESTART_WITH_NEW_ADDRESSES
%token <reserved> USER_INITIATED_ABORT PROTOCOL_VIOLATION
%token <reserved> STALENESS CHK PARAM UNRECOGNIZED_PARAMETERS
%token <reserved> SPP_ASSOC_ID SPP_ADDRESS SPP_HBINTERVAL SPP_PATHMAXRXT SPP_PATHMTU
%token <reserved> SPP_FLAGS SPP_IPV6_FLOWLABEL_ SPP_DSCP_
%token <reserved> SASOC_ASOCMAXRXT SASOC_ASSOC_ID SASOC_NUMBER_PEER_DESTINATIONS SASOC_PEER_RWND
%token <reserved> SASOC_LOCAL_RWND SASOC_COOKIE_LIFE SE_ASSOC_ID SE_TYPE SE_ON
%token <reserved> SND_SID SND_FLAGS SND_PPID SND_CONTEXT SND_ASSOC_ID SSB_ADAPTATION_IND
%token <reserved> BAD_CRC32C NULL_
%token <reserved> SINFO_STREAM SINFO_SSN SINFO_FLAGS SINFO_PPID SINFO_CONTEXT SINFO_ASSOC_ID
%token <reserved> SINFO_TIMETOLIVE SINFO_TSN SINFO_CUMTSN SINFO_PR_VALUE SERINFO_NEXT_FLAGS
%token <reserved> SERINFO_NEXT_STREAM SERINFO_NEXT_AID SERINFO_NEXT_LENGTH SERINFO_NEXT_PPID
%token <reserved> PR_POLICY PR_VALUE PR_ASSOC_ID AUTH_KEYNUMBER SENDV_FLAGS SENDV_SNDINFO
%token <reserved> RCV_SID RCV_SSN RCV_FLAGS RCV_PPID RCV_TSN RCV_CUMTSN RCV_CONTEXT RCV_ASSOC_ID
%token <reserved> NXT_SID NXT_FLAGS NXT_PPID NXT_LENGTH NXT_ASSOC_ID
%token <reserved> SSE_TYPE SSE_FLAGS SSE_LENGTH SSE_ASSOC_ID
%token <reserved> SENDER_DRY_TYPE SENDER_DRY_FLAGS SENDER_DRY_LENGTH SENDER_DRY_ASSOC_ID
%token <reserved> _SCTP_DATA_IO_EVENT_ _SCTP_ASSOCIATION_EVENT_ _SCTP_ADDRESS_EVENT_
%token <reserved> _SCTP_SEND_FAILURE_EVENT_ _SCTP_PEER_ERROR_EVENT_ _SCTP_SHUTDOWN_EVENT_
%token <reserved> _SCTP_PARTIAL_DELIVERY_EVENT_ _SCTP_ADAPTATION_LAYER_EVENT_
%token <reserved> _SCTP_AUTHENTICATION_EVENT_ _SCTP_SENDER_DRY_EVENT_
%token <reserved> SAC_TYPE SAC_FLAGS SAC_LENGTH SAC_STATE SAC_ERROR SAC_OUTBOUND_STREAMS
%token <reserved> SAC_INBOUND_STREAMS SAC_ASSOC_ID SAC_INFO
%token <reserved> SSFE_TYPE SSFE_FLAGS SSFE_LENGTH SSFE_ERROR SSFE_INFO SSFE_ASSOC_ID SSFE_DATA
%token <reserved> AUTH_TYPE AUTH_FLAGS AUTH_LENGTH AUTH_INDICATION AUTH_ASSOC_ID
%token <reserved> SRE_TYPE SRE_FLAGS SRE_LENGTH SRE_ERROR SRE_ASSOC_ID SRE_DATA PDAPI_ASSOC_ID
%token <reserved> PDAPI_TYPE PDAPI_FLAGS PDAPI_LENGTH PDAPI_INDICATION PDAPI_STREAM PDAPI_SEQ
%token <reserved> SPC_TYPE SPC_FLAGS SPC_LENGTH SPC_AADDR SPC_STATE SPC_ERROR SPC_ASSOC_ID
%token <reserved> SSF_TYPE SSF_LENGTH SSF_FLAGS SSF_ERROR SSF_INFO SSF_ASSOC_ID SSF_DATA
%token <reserved> SAI_TYPE SAI_FLAGS SAI_LENGTH SAI_ADAPTATION_IND SAI_ASSOC_ID
%token <reserved> GAIDS_NUMBER_OF_IDS GAIDS_ASSOC_ID SSPP_ASSOC_ID SSPP_ADDR
%token <reserved> SN_TYPE SN_FLAGS SN_LENGTH SAUTH_CHUNK
%token <reserved> SCA_ASSOC_ID SCA_KEYNUMBER SCA_KEYLENGTH SCA_KEY
%token <reserved> SRS_ASSOC_ID SRS_FLAGS SRS_NUMBER_STREAMS SRS_STREAM_LIST
%token <reserved> SAS_ASSOC_ID SAS_INSTRMS SAS_OUTSTRMS
%token <reserved> STRRESET_TYPE STRRESET_FLAGS STRRESET_LENGTH STRRESET_ASSOC_ID STRRESET_STREAM_LIST
%token <reserved> ASSOCRESET_TYPE ASSOCRESET_FLAGS ASSOCRESET_LENGTH ASSOCRESET_ASSOC_ID ASSOCRESET_LOCAL_TSN ASSOCRESET_REMOTE_TSN
%token <reserved> STRCHANGE_TYPE STRCHANGE_FLAGS STRCHANGE_LENGTH STRCHANGE_ASSOC_ID STRCHANGE_INSTRMS STRCHANGE_OUTSTRMS
%token <reserved> SUE_ASSOC_ID SUE_ADDRESS SUE_PORT
%token <floating> FLOAT
%token <integer> INTEGER HEX_INTEGER
%token <string> WORD STRING BACK_QUOTED CODE IPV4_ADDR IPV6_ADDR
%type <ignore_integer> ignore_integer
%type <direction> direction
%type <ip_ecn> opt_ip_info
%type <ip_ecn> ip_ecn
%type <option> option options opt_options
%type <event> event events event_time action
%type <time_usecs> time opt_end_time
%type <packet> packet_spec
%type <packet> sctp_packet_spec tcp_packet_spec
%type <packet> udp_packet_spec udplite_packet_spec
%type <packet> packet_prefix
%type <syscall> syscall_spec
%type <command> command_spec
%type <code> code_spec
%type <mpls_stack> mpls_stack
%type <mpls_stack_entry> mpls_stack_entry
%type <integer> opt_mpls_stack_bottom
%type <integer> opt_icmp_mtu
%type <string> icmp_type opt_icmp_code flags
%type <string> opt_tcp_fast_open_cookie tcp_fast_open_cookie
%type <string> opt_note note word_list
%type <string> option_flag option_value script
%type <window> opt_window
%type <sequence_number> opt_ack
%type <tcp_sequence_info> seq
%type <transport_info> opt_icmp_echoed
%type <tcp_options> opt_tcp_options tcp_option_list
%type <tcp_option> tcp_option sack_block_list sack_block
%type <string> function_name
%type <expression_list> expression_list function_arguments
%type <expression> expression binary_expression array
%type <expression> decimal_integer hex_integer data
%type <expression> inaddr sockaddr msghdr cmsghdr cmsg_level cmsg_type cmsg_data
%type <expression> sf_hdtr iovec pollfd opt_revents
%type <expression> linger l_onoff l_linger
%type <expression> accept_filter_arg af_name af_arg
%type <expression> tcp_function_set function_set_name pcbcnt
%type <udp_encaps_info> opt_udp_encaps_info
%type <sctp_header_spec> sctp_header_spec
%type <expression> sctp_assoc_id
%type <expression> sctp_status sstat_state sstat_rwnd sstat_unackdata sstat_penddata
%type <expression> sstat_instrms sstat_outstrms sstat_fragmentation_point sstat_primary
%type <expression> sctp_initmsg sinit_num_ostreams sinit_max_instreams sinit_max_attempts
%type <expression> sinit_max_init_timeo sctp_assoc_value sctp_stream_value sctp_hmacalgo
%type <expression> shmac_number_of_idents
%type <expression> sctp_authkeyid scact_keynumber sctp_sackinfo sack_delay sack_freq
%type <expression> sctp_rtoinfo srto_initial srto_max srto_min sctp_paddrinfo
%type <expression> sctp_paddrparams spp_address spp_hbinterval spp_pathmtu spp_pathmaxrxt
%type <expression> spp_flags spp_ipv6_flowlabel spp_dscp ssp_addr
%type <expression> spinfo_address spinfo_state spinfo_cwnd spinfo_srtt spinfo_rto spinfo_mtu
hoelscher
committed
%type <expression> sctp_authchunks gauth_number_of_chunks
%type <expression> sasoc_asocmaxrxt sasoc_number_peer_destinations sasoc_peer_rwnd
%type <expression> sasoc_local_rwnd sasoc_cookie_life sctp_assocparams
%type <expression> sctp_sndinfo snd_sid snd_flags snd_ppid snd_context
%type <expression> sctp_event se_type se_on sctp_setadaptation sctp_setprim null
%type <expression> sctp_sndrcvinfo sinfo_stream sinfo_ssn sinfo_flags sinfo_ppid sinfo_context
%type <expression> sinfo_timetolive sinfo_tsn sinfo_cumtsn sinfo_pr_value serinfo_next_flags
%type <expression> serinfo_next_stream serinfo_next_aid serinfo_next_length serinfo_next_ppid sctp_extrcvinfo
%type <expression> sctp_prinfo sctp_authinfo pr_policy sctp_sendv_spa sctp_default_prinfo
%type <expression> sctp_rcvinfo rcv_sid rcv_ssn rcv_flags rcv_ppid rcv_tsn rcv_cumtsn rcv_context
%type <expression> sctp_nxtinfo nxt_sid nxt_flags nxt_ppid nxt_length sctp_recvv_rn
%type <expression> sctp_shutdown_event sse_type sse_flags sse_length
%type <expression> sctp_sender_dry_event sender_dry_type sender_dry_flags sender_dry_length
%type <expression> sctp_event_subscribe
%type <expression> sctp_assoc_change sac_type sac_flags sac_length sac_state sac_error sac_outbound_streams
%type <expression> sac_inbound_streams sac_info
%type <expression> sctp_send_failed_event ssfe_type ssfe_flags ssfe_length ssfe_error ssfe_data
%type <expression> sctp_authkey_event auth_type auth_flags auth_length auth_keynumber auth_indication
%type <expression> sctp_remote_error sre_type sre_flags sre_length sre_error sre_data
%type <expression> sctp_pdapi_event pdapi_type pdapi_flags pdapi_length pdapi_indication pdapi_stream pdapi_seq
%type <expression> sctp_paddr_change spc_type spc_flags spc_length spc_aaddr spc_error spc_state
%type <expression> sctp_send_failed ssf_type ssf_length ssf_flags ssf_error ssf_info ssf_data
%type <expression> sctp_adaptation_event sai_type sai_flags sai_length sai_adaptation_ind
%type <expression> sctp_tlv sn_type sn_flags sn_length sctp_assoc_ids gaids_number_of_ids
%type <expression> sctp_setpeerprim sctp_authchunk sctp_authkey
%type <expression> sctp_reset_streams srs_flags
%type <expression> sctp_stream_reset_event strreset_type strreset_flags strreset_length
%type <expression> sctp_assoc_reset_event assocreset_type assocreset_flags assocreset_length
%type <expression> assocreset_local_tsn assocreset_remote_tsn
%type <expression> sctp_stream_change_event strchange_type strchange_flags strchange_length strchange_instrms strchange_outstrms
%type <expression> sctp_udpencaps sue_address sue_port
%type <chunk_list> sctp_chunk_list_spec
%type <chunk_list_item> sctp_chunk_spec
%type <chunk_list_item> sctp_generic_chunk_spec
%type <chunk_list_item> sctp_data_chunk_spec
%type <chunk_list_item> sctp_init_chunk_spec sctp_init_ack_chunk_spec
%type <chunk_list_item> sctp_sack_chunk_spec sctp_nr_sack_chunk_spec
%type <chunk_list_item> sctp_heartbeat_chunk_spec sctp_heartbeat_ack_chunk_spec
%type <chunk_list_item> sctp_abort_chunk_spec
%type <chunk_list_item> sctp_shutdown_chunk_spec
%type <chunk_list_item> sctp_shutdown_ack_chunk_spec
%type <chunk_list_item> sctp_error_chunk_spec
%type <chunk_list_item> sctp_cookie_echo_chunk_spec sctp_cookie_ack_chunk_spec
%type <chunk_list_item> sctp_ecne_chunk_spec sctp_cwr_chunk_spec
%type <chunk_list_item> sctp_shutdown_complete_chunk_spec
%type <chunk_list_item> sctp_i_data_chunk_spec
%type <chunk_list_item> sctp_pad_chunk_spec sctp_reconfig_chunk_spec
%type <chunk_list_item> sctp_forward_tsn_spec sctp_i_forward_tsn_spec
%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec
%type <parameter_list_item> sctp_parameter_spec
%type <parameter_list_item> sctp_generic_parameter_spec
%type <parameter_list_item> sctp_heartbeat_information_parameter_spec
%type <parameter_list_item> sctp_ipv4_address_parameter_spec
%type <parameter_list_item> sctp_ipv6_address_parameter_spec
%type <parameter_list_item> sctp_state_cookie_parameter_spec
%type <parameter_list_item> sctp_unrecognized_parameter_parameter_spec
%type <parameter_list_item> sctp_cookie_preservative_parameter_spec
%type <parameter_list_item> sctp_hostname_address_parameter_spec
%type <parameter_list_item> sctp_supported_address_types_parameter_spec
%type <parameter_list_item> sctp_ecn_capable_parameter_spec
Aomx
committed
%type <parameter_list_item> sctp_fornward_tsn_supported_spec
%type <parameter_list_item> sctp_supported_extensions_parameter_spec
%type <parameter_list_item> sctp_adaptation_indication_parameter_spec
%type <parameter_list_item> sctp_pad_parameter_spec
%type <parameter_list_item> outgoing_ssn_reset_request incoming_ssn_reset_request
%type <parameter_list_item> reconfig_response ssn_tsn_reset_request generic_reconfig_request
%type <parameter_list_item> add_outgoing_streams_request add_incoming_streams_request
%type <cause_list> opt_cause_list_spec sctp_cause_list_spec
%type <cause_list_item> sctp_cause_spec
%type <cause_list_item> sctp_generic_cause_spec
%type <cause_list_item> sctp_invalid_stream_identifier_cause_spec
%type <cause_list_item> sctp_missing_mandatory_parameter_cause_spec
%type <cause_list_item> sctp_stale_cookie_error_cause_spec
%type <cause_list_item> sctp_out_of_resources_cause_spec
%type <cause_list_item> sctp_unresolvable_address_cause_spec
%type <cause_list_item> sctp_unrecognized_chunk_type_cause_spec
%type <cause_list_item> sctp_invalid_mandatory_parameter_cause_spec
%type <cause_list_item> sctp_unrecognized_parameters_cause_spec
%type <cause_list_item> sctp_no_user_data_cause_spec
%type <cause_list_item> sctp_cookie_received_while_shutdown_cause_spec
%type <cause_list_item> sctp_restart_with_new_addresses_cause_spec
%type <cause_list_item> sctp_user_initiated_abort_cause_spec
%type <cause_list_item> sctp_protocol_violation_cause_spec
%type <integer> chunk_type opt_chunk_type opt_parameter_type opt_cause_code
%type <integer> opt_flags opt_data_flags opt_abort_flags
%type <integer> opt_shutdown_complete_flags opt_i_data_flags opt_len
%type <integer> opt_tag opt_a_rwnd opt_os opt_is opt_tsn opt_sid opt_ssn
%type <integer> opt_cum_tsn opt_ppid opt_sender_next_tsn opt_receiver_next_tsn
%type <integer> opt_req_sn opt_resp_sn opt_last_tsn opt_result opt_number_of_new_streams
%type <byte_list> opt_val opt_info byte_list chunk_types_list
%type <u16_list> u16_list
%type <u16_item> u16_item
%type <sack_block_list> opt_gaps opt_nr_gaps gap_list opt_dups dup_list
%type <sack_block_list_item> gap dup
%type <forward_tsn_ids_list> opt_stream_identifier ids_list
%type <i_forward_tsn_ids_list> opt_i_forward_tsn_stream_identifier i_forward_tsn_ids_list
%type <i_forward_tsn_ids_list_item> i_forward_tsn_id
%type <address_type_list> address_types_list
%type <address_type_list_item> address_type
%type <parameter_type_list> parameter_types_list
%type <parameter_type_list_item> parameter_type
%% /* The grammar follows. */
script
: opt_options opt_init_command events opt_cleanup_command {
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
$$ = NULL; /* The parser output is in out_script */
}
;
opt_options
: {
$$ = NULL;
parse_and_finalize_config(invocation);
}
| options {
$$ = $1;
parse_and_finalize_config(invocation);
}
;
options
: option {
out_script->option_list = $1;
$$ = $1; /* return the tail so we can append to it */
}
| options option {
$1->next = $2;
$$ = $2; /* return the tail so we can append to it */
}
;
option
: option_flag '=' option_value {
$$ = new_option($1, $3);
}
| option_flag {
$$ = new_option($1, NULL);
}
option_flag
: OPTION { $$ = $1; }
;
option_value
: INTEGER { $$ = strdup(yytext); }
| WORD { $$ = $1; }
| STRING { $$ = $1; }
| IPV4_ADDR { $$ = $1; }
| IPV6_ADDR { $$ = $1; }
| IPV4 { $$ = strdup("ipv4"); }
| IPV6 { $$ = strdup("ipv6"); }
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
| WORD '=' INTEGER {
/* For consistency, allow syntax like: --define=PROTO=132 */
char *lhs = $1;
s64 rhs = $3;
asprintf(&($$), "%s=%lld", lhs, rhs);
free(lhs);
}
| WORD '=' WORD {
/* For consistency, allow syntax like: --define=PROTO=IPPROTO_TCP */
char *lhs = $1, *rhs = $3;
asprintf(&($$), "%s=%s", lhs, rhs);
free(lhs);
free(rhs);
}
| WORD '=' STRING {
/* For consistency, allow syntax like: --define=CC="reno" */
char *lhs = $1, *rhs = $3;
asprintf(&($$), "%s=\"%s\"", lhs, rhs);
free(lhs);
free(rhs);
}
| WORD '=' BACK_QUOTED {
/* For consistency, allow syntax like: --define=SCRIPT=`cleanup` */
char *lhs = $1, *rhs = $3;
asprintf(&($$), "%s=`%s`", lhs, rhs);
free(lhs);
free(rhs);
}
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;
opt_init_command
: { }
| init_command { }
;
init_command
: command_spec { out_script->init_command = $1; }
;
events
: event {
out_script->event_list = $1; /* save pointer to event list as output
* of parser */
$$ = $1; /* return the tail so that we can append to it */
}
| events event {
$1->next = $2; /* link new event to the end of the existing list */
$$ = $2; /* return the tail so that we can append to it */
}
;
event
: event_time action {
$$ = $2;
$$->line_number = $1->line_number; /* use timestamp's line */
$$->time_usecs = $1->time_usecs;
$$->time_usecs_end = $1->time_usecs_end;
$$->time_type = $1->time_type;
if ($$->time_usecs_end != NO_TIME_RANGE) {
if ($$->time_usecs_end < $$->time_usecs)
semantic_error("time range is backwards");
}
if ($$->time_type == ANY_TIME && ($$->type != PACKET_EVENT ||
packet_direction($$->event.packet) != DIRECTION_OUTBOUND)) {
yylineno = $$->line_number;
semantic_error("event time <star> can only be used with "
"outbound packets");
} else if (($$->time_type == ABSOLUTE_RANGE_TIME ||
$$->time_type == RELATIVE_RANGE_TIME) &&
($$->type != PACKET_EVENT ||
packet_direction($$->event.packet) != DIRECTION_OUTBOUND)) {
yylineno = $$->line_number;
semantic_error("event time range can only be used with "
"outbound packets");
}
free($1);
}
;
event_time
: '+' time {
$$ = new_event(INVALID_EVENT);
$$->line_number = @2.first_line;
$$->time_usecs = $2;
$$->time_type = RELATIVE_TIME;
}
| time {
$$ = new_event(INVALID_EVENT);
$$->line_number = @1.first_line;
$$->time_usecs = $1;
$$->time_type = ABSOLUTE_TIME;
}
| '*' {
$$ = new_event(INVALID_EVENT);
$$->line_number = @1.first_line;
$$->time_type = ANY_TIME;
}
| time '~' time {
$$ = new_event(INVALID_EVENT);
$$->line_number = @1.first_line;
$$->time_type = ABSOLUTE_RANGE_TIME;
$$->time_usecs = $1;
$$->time_usecs_end = $3;
}
| '+' time '~' '+' time {
$$ = new_event(INVALID_EVENT);
$$->line_number = @1.first_line;
$$->time_type = RELATIVE_RANGE_TIME;
$$->time_usecs = $2;
$$->time_usecs_end = $5;
}
;
time
: FLOAT {
if ($1 < 0) {
semantic_error("negative time");
}
$$ = (s64)($1 * 1.0e6); /* convert float secs to s64 microseconds */
}
| INTEGER {
if ($1 < 0) {
semantic_error("negative time");
}
$$ = (s64)($1 * 1000000); /* convert int secs to s64 microseconds */
}
;
action
: packet_spec { $$ = new_event(PACKET_EVENT); $$->event.packet = $1; }
| syscall_spec { $$ = new_event(SYSCALL_EVENT); $$->event.syscall = $1; }
| command_spec { $$ = new_event(COMMAND_EVENT); $$->event.command = $1; }
| code_spec { $$ = new_event(CODE_EVENT); $$->event.code = $1; }
;