diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 8e8e7f89ed95072d8427b913e7b60b724e9f75ef..4e9e3e8419d6c81b54a6a9910d5dde7544e971e3 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -203,6 +203,8 @@ noecn return NO_ECN; ce return CE; [.][.][.] return ELLIPSIS; assoc_value return ASSOC_VALUE; +stream_id return STREAM_ID; +stream_value return STREAM_VALUE; sack_delay return SACK_DELAY; sack_freq return SACK_FREQ; srto_initial return SRTO_INITIAL; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 88deb4f9a8029964404f6f9d2c2a3e99dcd28985..07bee01aa33ba10a39a33e144cf686249b9427b4 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -506,6 +506,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %token <reserved> SINIT_NUM_OSTREAMS SINIT_MAX_INSTREAMS SINIT_MAX_ATTEMPTS %token <reserved> SINIT_MAX_INIT_TIMEO %token <reserved> ASSOC_VALUE +%token <reserved> STREAM_ID STREAM_VALUE %token <reserved> SACK_DELAY SACK_FREQ %token <reserved> SSTAT_STATE SSTAT_RWND SSTAT_UNACKDATA SSTAT_PENDDATA %token <reserved> SSTAT_INSTRMS SSTAT_OUTSTRMS SSTAT_FRAGMENTATION_POINT @@ -569,6 +570,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <expression> linger l_onoff l_linger %type <expression> sctp_status sctp_initmsg sctp_sackinfo %type <expression> sctp_assoc_value +%type <expression> sctp_stream_value %type <expression> sctp_rtoinfo srto_initial srto_max srto_min %type <errno_info> opt_errno %type <chunk_list> sctp_chunk_list_spec @@ -2337,6 +2339,9 @@ expression | sctp_assoc_value { $$ = $1; } +| sctp_stream_value { + $$ = $1; +} | sctp_sackinfo { $$ = $1; } @@ -2561,6 +2566,19 @@ sctp_initmsg } ; +sctp_stream_value +: '{' STREAM_ID '=' expression ',' STREAM_VALUE '=' expression '}' { +#if defined(SCTP_SS_VALUE) + $$ = new_expression(EXPR_SCTP_STREAM_VALUE); + $$->value.sctp_stream_value = calloc(1, sizeof(struct sctp_stream_value_expr)); + $$->value.sctp_stream_value->stream_id = $4; + $$->value.sctp_stream_value->stream_value = $8; +#else + $$ = NULL; +#endif +} +; + sctp_assoc_value : '{' ASSOC_VALUE '=' expression '}' { #if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index a130404fbec2a5c375d436217e152360c7cccba4..f3a3d1bb4f6aae403925bf163415b22ec1787c32 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -180,6 +180,26 @@ static int check_type(struct expression *expression, } } +/* Sets the value from the expression argument, checking that it is a + * valid u16, and matches the expected type. Returns STATUS_OK on + * success; on failure returns STATUS_ERR and sets error message. + */ +static int get_u16(struct expression *expression, + u16 *value, char **error) +{ + if (check_type(expression, EXPR_INTEGER, error)) + return STATUS_ERR; + if ((expression->value.num > UINT16_MAX) || + (expression->value.num < 0)) { + asprintf(error, + "Value out of range for 16-bit unsigned integer: %lld", + expression->value.num); + return STATUS_ERR; + } + *value = expression->value.num; + return STATUS_OK; +} + /* Sets the value from the expression argument, checking that it is a * valid u32, and matches the expected type. Returns STATUS_OK on * success; on failure returns STATUS_ERR and sets error message. @@ -1636,6 +1656,18 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, live_optval = malloc(sizeof(struct sctp_assoc_value)); live_optlen = (socklen_t)sizeof(struct sctp_assoc_value); ((struct sctp_assoc_value *) live_optval)->assoc_id = 0; +#endif +#ifdef SCTP_SS_VALUE + } else if (val_expression->type == EXPR_SCTP_STREAM_VALUE) { + live_optval = malloc(sizeof(struct sctp_stream_value)); + live_optlen = (socklen_t)sizeof(struct sctp_stream_value); + ((struct sctp_stream_value *) live_optval)->assoc_id = 0; + if (get_u16(val_expression->value.sctp_stream_value->stream_id, + &((struct sctp_stream_value *) live_optval)->stream_id, + error)) { + free(live_optval); + return STATUS_ERR; + } #endif } else { s32_bracketed_arg(args, 3, &script_optval, error); @@ -1788,6 +1820,38 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, return STATUS_ERR; } } +#endif +#ifdef SCTP_SS_VALUE + } else if (val_expression->type == EXPR_SCTP_STREAM_VALUE) { + struct expression *stream_id = val_expression->value.sctp_stream_value->stream_id; + struct expression *stream_value = val_expression->value.sctp_stream_value->stream_value; + struct sctp_stream_value *sctp_stream_value = live_optval; + u16 value; + + if (stream_id->type != EXPR_ELLIPSIS) { + if (get_u16(stream_id, &value, error)) { + free(live_optval); + return STATUS_ERR; + } + if (sctp_stream_value->stream_id != value) { + asprintf(error, "Bad getsockopt sctp_stream_value.stream_id: expected: %u actual: %u", + value, sctp_stream_value->stream_id); + free(live_optval); + return STATUS_ERR; + } + } + if (stream_value->type != EXPR_ELLIPSIS) { + if (get_u16(stream_value, &value, error)) { + free(live_optval); + return STATUS_ERR; + } + if (sctp_stream_value->stream_value != value) { + asprintf(error, "Bad getsockopt sctp_stream_value.stream_value: expected: %u actual: %u", + value, sctp_stream_value->stream_value); + free(live_optval); + return STATUS_ERR; + } + } #endif } else { if (*(int*)live_optval != script_optval) { @@ -1807,7 +1871,12 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, int script_fd, live_fd, level, optname, optval_s32, optlen, result; void *optval = NULL; struct expression *val_expression; +#if defined(SCTP_MAXSEG) || defined(SCTP_MAX_BURST) || defined(SCTP_INTERLEAVING_SUPPORTED) struct sctp_assoc_value assoc_value; +#endif +#if defined(SCTP_SS_VALUE) + struct sctp_stream_value stream_value; +#endif if (check_arg_count(args, 5, error)) return STATUS_ERR; @@ -1867,6 +1936,19 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, } optval = &assoc_value; #endif +#ifdef SCTP_SS_VALUE + } else if (val_expression->type == EXPR_SCTP_STREAM_VALUE) { + stream_value.assoc_id = 0; + if (get_u16(val_expression->value.sctp_stream_value->stream_id, + &stream_value.stream_id, error)) { + return STATUS_ERR; + } + if (get_u16(val_expression->value.sctp_stream_value->stream_value, + &stream_value.stream_value, error)) { + return STATUS_ERR; + } + optval = &stream_value; +#endif #ifdef SCTP_DELAYED_SACK } else if (val_expression->type == EXPR_SCTP_SACKINFO) { optval = &val_expression->value.sctp_sack_info; diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index 3592bd39e73511ddc1e1bc4eb8fa567ff400a300..b28360fd9457bcbe7274c5617b1032c3bb001004 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -79,6 +79,9 @@ struct expression_type_entry expression_type_table[] = { #endif #ifdef SCTP_STATUS { EXPR_SCTP_STATUS, "sctp_status"}, +#endif +#ifdef SCTP_SS_VALUE + { EXPR_SCTP_STREAM_VALUE, "sctp_stream_value"}, #endif { NUM_EXPR_TYPES, NULL} }; @@ -312,6 +315,12 @@ void free_expression(struct expression *expression) case EXPR_SCTP_STATUS: #endif break; +#ifdef SCTP_SS_VALUE + case EXPR_SCTP_STREAM_VALUE: + free(expression->value.sctp_stream_value->stream_id); + free(expression->value.sctp_stream_value->stream_value); + break; +#endif case EXPR_WORD: assert(expression->value.string); free(expression->value.string); @@ -521,6 +530,32 @@ static int evaluate_sctp_assoc_value_expression(struct expression *in, } #endif +#ifdef SCTP_SS_VALUE +static int evaluate_sctp_stream_value_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct sctp_stream_value_expr *in_value; + struct sctp_stream_value_expr *out_value; + + assert(in->type == EXPR_SCTP_STREAM_VALUE); + assert(in->value.sctp_stream_value); + assert(out->type == EXPR_SCTP_STREAM_VALUE); + + out->value.sctp_stream_value = calloc(1, sizeof(struct sctp_stream_value_expr)); + + in_value = in->value.sctp_stream_value; + out_value = out->value.sctp_stream_value; + + if (evaluate(in_value->stream_id, &out_value->stream_id, error)) + return STATUS_ERR; + if (evaluate(in_value->stream_value, &out_value->stream_value, error)) + return STATUS_ERR; + + return STATUS_OK; +} +#endif + static int evaluate(struct expression *in, struct expression **out_ptr, char **error) { @@ -572,6 +607,11 @@ static int evaluate(struct expression *in, memcpy(&out->value.sctp_status, &in->value.sctp_status, sizeof(in->value.sctp_status)); break; +#endif +#ifdef SCTP_SS_VALUE + case EXPR_SCTP_STREAM_VALUE: + evaluate_sctp_stream_value_expression(in, out, error); + break; #endif case EXPR_WORD: out->type = EXPR_INTEGER; diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index 3fc9ca95b3b3766de85e675e4300891b9b029c65..a7fc401417adc7110625cbc87ac4714948519db1 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -60,6 +60,9 @@ enum expression_t { #endif #ifdef SCTP_STATUS EXPR_SCTP_STATUS, /* struct sctp_status for SCTP_STATUS */ +#endif +#ifdef SCTP_SS_VALUE + EXPR_SCTP_STREAM_VALUE, /* struct sctp_stream_value for SCTP_SS_VALUE */ #endif NUM_EXPR_TYPES, }; @@ -94,6 +97,9 @@ struct expression { #endif #ifdef SCTP_STATUS struct sctp_status sctp_status; +#endif +#ifdef SCTP_SS_VALUE + struct sctp_stream_value_expr *sctp_stream_value; #endif } value; const char *format; /* the printf format for printing the value */ @@ -157,6 +163,14 @@ struct sctp_assoc_value_expr { }; #endif +#ifdef SCTP_SS_VALUE +/* Parse tree for a sctp_stream_value struct in a [gs]etsockopt syscall. */ +struct sctp_stream_value_expr { + struct expression *stream_id; + struct expression *stream_value; +}; +#endif + /* The errno-related info from strace to summarize a system call error */ struct errno_spec { const char *errno_macro; /* errno symbol (C macro name) */ diff --git a/gtests/net/packetdrill/symbols_freebsd.c b/gtests/net/packetdrill/symbols_freebsd.c index ffc7d6cba0362ebcc045fc07e1c32115d3c21b5d..ad5231e60c2ca275dd57a6b61feab0227b95b2b1 100644 --- a/gtests/net/packetdrill/symbols_freebsd.c +++ b/gtests/net/packetdrill/symbols_freebsd.c @@ -105,6 +105,7 @@ struct int_symbol platform_symbols_table[] = { * The old symbols currently being deployed are also provided. */ { SCTP_PLUGGABLE_SS, "SCTP_PLUGGABLE_SS" }, + { SCTP_SS_VALUE, "SCTP_SS_VALUE" }, { SCTP_SS_DEFAULT, "SCTP_SS_DEFAULT" }, { SCTP_SS_ROUND_ROBIN, "SCTP_SS_ROUND_ROBIN" }, { SCTP_SS_ROUND_ROBIN_PACKET, "SCTP_SS_ROUND_ROBIN_PACKET" },