From 8b597a00f6a8f73834c56dd0cefb3607aa748c82 Mon Sep 17 00:00:00 2001 From: Michael Tuexen <tuexen@fh-muenster.de> Date: Tue, 2 Jun 2020 08:17:01 +0200 Subject: [PATCH] Add support for struct tcp_fastopen in FreeBSD. --- gtests/net/packetdrill/lexer.l | 2 + gtests/net/packetdrill/parser.y | 49 +++++++++++++- gtests/net/packetdrill/run_system_call.c | 84 ++++++++++++++++++++++++ gtests/net/packetdrill/script.c | 76 +++++++++++++++++++++ gtests/net/packetdrill/script.h | 8 +++ 5 files changed, 218 insertions(+), 1 deletion(-) diff --git a/gtests/net/packetdrill/lexer.l b/gtests/net/packetdrill/lexer.l index 316bf385..74b52871 100644 --- a/gtests/net/packetdrill/lexer.l +++ b/gtests/net/packetdrill/lexer.l @@ -254,6 +254,8 @@ af_name return AF_NAME; af_arg return AF_ARG; function_set_name return FUNCTION_SET_NAME; pcbcnt return PCBCNT; +enable return ENABLE; +psk return PSK; assoc_id return ASSOC_ID; assoc_value return ASSOC_VALUE; shmac_number_of_idents return SHMAC_NUMBER_OF_IDENTS; diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index f55e9378..78fc5018 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -573,6 +573,7 @@ static struct tcp_option *new_tcp_exp_fast_open_option(const char *cookie_string %token <reserved> OPTION %token <reserved> AF_NAME AF_ARG %token <reserved> FUNCTION_SET_NAME PCBCNT +%token <reserved> ENABLE PSK %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 @@ -691,6 +692,7 @@ static struct tcp_option *new_tcp_exp_fast_open_option(const char *cookie_string %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 <expression> tcp_fastopen enable psk %type <udp_encaps_info> opt_udp_encaps_info %type <sctp_header_spec> sctp_header_spec %type <expression> sctp_assoc_id @@ -3017,6 +3019,9 @@ expression | tcp_function_set { $$ = $1; } +| tcp_fastopen { + $$ = $1; +} | sf_hdtr { $$ = $1; } @@ -3436,6 +3441,48 @@ tcp_function_set } ; +enable +: ENABLE '=' INTEGER { + if (!is_valid_u32($3)) { + semantic_error("linger out of range"); + } + $$ = new_integer_expression($3, "%lu"); +} +| ENABLE '=' HEX_INTEGER { + if (!is_valid_u32($3)) { + semantic_error("linger out of range"); + } + $$ = new_integer_expression($3, "%lu"); +} +| ENABLE '=' ELLIPSIS { + $$ = new_expression(EXPR_ELLIPSIS); +} +; + +psk +: PSK '=' WORD { + $$ = new_expression(EXPR_HEX_WORD); + $$->value.string = $3; +} +| PSK '=' ELLIPSIS { + $$ = new_expression(EXPR_ELLIPSIS); +} +; + + +tcp_fastopen +: '{' enable ',' psk '}' { +#if defined(__FreeBSD__) + $$ = new_expression(EXPR_TCP_FASTOPEN); + $$->value.tcp_fastopen = calloc(1, sizeof(struct tcp_fastopen_expr)); + $$->value.tcp_fastopen->enable = $2; + $$->value.tcp_fastopen->psk = $4; +#else + $$ = NULL; +#endif +} +; + sf_hdtr : '{' SF_HDTR_HEADERS '(' decimal_integer ')' '=' array ',' SF_HDTR_TRAILERS '('decimal_integer ')' '=' array '}' { @@ -3458,7 +3505,7 @@ srto_initial if (!is_valid_u32($3)){ semantic_error("srto_initial out of range"); } - $$ = new_integer_expression($3, "%u"); + $$ = new_integer_expression($3, "%u"); } | SRTO_INITIAL '=' ELLIPSIS { $$ = new_expression(EXPR_ELLIPSIS); } ; diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index 773409c0..198f853c 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -3362,6 +3362,39 @@ static int check_tcp_function_set(struct tcp_function_set_expr *expr, } #endif +#ifdef __FreeBSD__ +static int check_tcp_fastopen(struct tcp_fastopen_expr *expr, + struct tcp_fastopen *tcp_fastopen, + char **error) { + unsigned int i; + + if (check_s32_expr(expr->enable, tcp_fastopen->enable, + "tcp_fastopen.enable", error)) + return STATUS_ERR; + if (expr->psk->type != EXPR_ELLIPSIS) { + if (strlen(expr->psk->value.string) != 2 * TCP_FASTOPEN_PSK_LEN) { + asprintf(error, "tcp_fastopen.psk: expected length: %zd, actual length: %d\n", + strlen(expr->psk->value.string), + TCP_FASTOPEN_PSK_LEN); + return STATUS_ERR; + } + for (i = 0; i < TCP_FASTOPEN_PSK_LEN; i++) { + char buf[3]; + + buf[0] = expr->psk->value.string[2 * i]; + buf[1] = expr->psk->value.string[2 * i + 1]; + buf[2] = '\0'; + if (tcp_fastopen->psk[i] != (uint8_t)strtoul(buf, NULL, 16)) { + asprintf(error, "tcp_fastopen.psk[%u]: expected: 0x%s, actual: 0x%02x\n", + i, buf, tcp_fastopen->psk[i]); + return STATUS_ERR; + } + } + } + return STATUS_OK; +} +#endif + static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, struct expression_list *args, char **error) { @@ -3705,6 +3738,16 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, live_optlen = (socklen_t)sizeof(struct tcp_function_set); break; } +#endif +#ifdef __FreeBSD__ + case EXPR_TCP_FASTOPEN: { + struct tcp_fastopen *live_tcp_fastopen = malloc(sizeof(struct tcp_fastopen)); + + memset(live_tcp_fastopen, 0, sizeof(struct tcp_fastopen)); + live_optval = live_tcp_fastopen; + live_optlen = (socklen_t)sizeof(struct tcp_fastopen); + break; + } #endif case EXPR_LIST: s32_bracketed_arg(args, 3, &script_optval, error); @@ -3867,6 +3910,11 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_TCP_FUNCTION_SET: result = check_tcp_function_set(val_expression->value.tcp_function_set, live_optval, error); break; +#endif +#ifdef __FreeBSD__ + case EXPR_TCP_FASTOPEN: + result = check_tcp_fastopen(val_expression->value.tcp_fastopen, live_optval, error); + break; #endif case EXPR_LIST: if (*(int*)live_optval != script_optval) { @@ -3975,6 +4023,9 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, #ifdef TCP_FUNCTION_BLK struct tcp_function_set tcp_function_set; #endif +#ifdef __FreeBSD__ + struct tcp_fastopen tcp_fastopen; +#endif if (check_arg_count(args, 5, error)) return STATUS_ERR; @@ -4673,6 +4724,39 @@ static int syscall_setsockopt(struct state *state, struct syscall_spec *syscall, optlen = (socklen_t)sizeof(struct tcp_function_set); } break; +#endif +#ifdef __FreeBSD__ + case EXPR_TCP_FASTOPEN: { + unsigned int i, len; + const char *hexstring = val_expression->value.tcp_fastopen->psk->value.string; + + memset(&tcp_fastopen, 0, sizeof(struct tcp_fastopen)); + if (get_s32(val_expression->value.tcp_fastopen->enable, + &tcp_fastopen.enable, error)) { + return STATUS_ERR; + } + if (check_type(val_expression->value.tcp_fastopen->psk, EXPR_HEX_WORD, error)) { + return STATUS_ERR; + } + len = (unsigned int)strlen(hexstring) / 2; + if (len > TCP_FASTOPEN_PSK_LEN) { + asprintf(error, "psk too long: %s", hexstring); + return STATUS_ERR; + } + for (i = 0; i < len; i ++) { + char buf[3]; + + buf[0] = hexstring[2 * i]; + buf[1] = hexstring[2 * i + 1]; + buf[2] = '\0'; + tcp_fastopen.psk[i] = (uint8_t)strtoul(buf, NULL, 16); + } + optval = &tcp_fastopen; + if (!optlen_provided) { + optlen = (socklen_t)sizeof(struct tcp_fastopen); + } + break; + } #endif default: asprintf(error, "unsupported value type: %s", diff --git a/gtests/net/packetdrill/script.c b/gtests/net/packetdrill/script.c index 3fc360fb..26e28a72 100644 --- a/gtests/net/packetdrill/script.c +++ b/gtests/net/packetdrill/script.c @@ -24,6 +24,7 @@ #include "script.h" +#include <ctype.h> #include <fcntl.h> #include <poll.h> #include <stdlib.h> @@ -108,6 +109,7 @@ struct expression_type_entry expression_type_table[] = { { EXPR_ELLIPSIS, "ellipsis" }, { EXPR_INTEGER, "integer" }, { EXPR_WORD, "word" }, + { EXPR_HEX_WORD, "hex word" }, { EXPR_STRING, "string" }, { EXPR_SOCKET_ADDRESS_IPV4, "sockaddr_in" }, { EXPR_SOCKET_ADDRESS_IPV6, "sockaddr_in6" }, @@ -124,6 +126,7 @@ struct expression_type_entry expression_type_table[] = { #if defined(__FreeBSD__) { EXPR_SF_HDTR, "sf_hdtr" }, { EXPR_TCP_FUNCTION_SET, "tcp_function_set" }, + { EXPR_TCP_FASTOPEN, "tcp_fastopen" }, #endif { EXPR_SCTP_RTOINFO, "sctp_rtoinfo" }, { EXPR_SCTP_INITMSG, "sctp_initmsg" }, @@ -370,6 +373,34 @@ static int unescape_cstring_expression(const char *input_string, return STATUS_OK; } +static int hex_word_expression(const char *input_string, + struct expression *out, char **error) +{ + size_t bytes = strlen(input_string) + 1; + out->type = EXPR_HEX_WORD; + out->value.string = (char *)malloc(bytes); + const char *c_in = input_string; + char *c_out = out->value.string; + + if ((bytes - 1)% 2) { + asprintf(error, "odd number of hexadecimal digits: %zu", bytes); + return STATUS_ERR; + } + while (*c_in != '\0') { + if (isxdigit(*c_in)) { + *c_out = toupper(*c_in); + } else { + asprintf(error, "unsupported hexadecimal digit: '%c'", + *c_in); + return STATUS_ERR; + } + ++c_in; + ++c_out; + } + *c_out = *c_in; + return STATUS_OK; +} + void free_expression(struct expression *expression) { if (expression == NULL) @@ -403,6 +434,12 @@ void free_expression(struct expression *expression) free_expression(expression->value.tcp_function_set->pcbcnt); free(expression->value.tcp_function_set); break; + case EXPR_TCP_FASTOPEN: + assert(expression->value.tcp_fastopen); + free_expression(expression->value.tcp_fastopen->enable); + free_expression(expression->value.tcp_fastopen->psk); + free(expression->value.tcp_fastopen); + break; #endif case EXPR_SCTP_RTOINFO: assert(expression->value.sctp_rtoinfo); @@ -818,6 +855,10 @@ void free_expression(struct expression *expression) assert(expression->value.string); free(expression->value.string); break; + case EXPR_HEX_WORD: + assert(expression->value.string); + free(expression->value.string); + break; case EXPR_STRING: assert(expression->value.string); free(expression->value.string); @@ -1139,6 +1180,34 @@ static int evaluate_tcp_function_set_expression(struct expression *in, return STATUS_OK; } +static int evaluate_tcp_fastopen_expression(struct expression *in, + struct expression *out, + char **error) +{ + struct tcp_fastopen_expr *in_tcp_fastopen; + struct tcp_fastopen_expr *out_tcp_fastopen; + + assert(in->type == EXPR_TCP_FASTOPEN); + assert(in->value.tcp_fastopen); + assert(out->type == EXPR_TCP_FASTOPEN); + + out->value.tcp_fastopen = calloc(1, sizeof(struct tcp_fastopen_expr)); + + in_tcp_fastopen = in->value.tcp_fastopen; + out_tcp_fastopen = out->value.tcp_fastopen; + + if (evaluate(in_tcp_fastopen->enable, + &out_tcp_fastopen->enable, + error)) + return STATUS_ERR; + if (evaluate(in_tcp_fastopen->psk, + &out_tcp_fastopen->psk, + error)) + return STATUS_ERR; + + return STATUS_OK; +} + static int evaluate_sf_hdtr_expression(struct expression *in, struct expression *out, char **error) { @@ -3016,6 +3085,9 @@ static int evaluate(struct expression *in, case EXPR_TCP_FUNCTION_SET: result = evaluate_tcp_function_set_expression(in, out, error); break; + case EXPR_TCP_FASTOPEN: + result = evaluate_tcp_fastopen_expression(in, out, error); + break; #endif case EXPR_SCTP_RTOINFO: result = evaluate_sctp_rtoinfo_expression(in, out, error); @@ -3164,6 +3236,10 @@ static int evaluate(struct expression *in, &out->value.num, error)) return STATUS_ERR; break; + case EXPR_HEX_WORD: + if (hex_word_expression(in->value.string, out, error)) + return STATUS_ERR; + break; case EXPR_STRING: if (unescape_cstring_expression(in->value.string, out, error)) return STATUS_ERR; diff --git a/gtests/net/packetdrill/script.h b/gtests/net/packetdrill/script.h index 5e21a2c5..50edcdc2 100644 --- a/gtests/net/packetdrill/script.h +++ b/gtests/net/packetdrill/script.h @@ -38,6 +38,7 @@ enum expression_t { EXPR_INTEGER, /* integer in 'num' */ EXPR_LINGER, /* struct linger for SO_LINGER */ EXPR_WORD, /* unquoted word in 'string' */ + EXPR_HEX_WORD, /* unquoted hex word in 'string' */ EXPR_STRING, /* double-quoted string in 'string' */ EXPR_SOCKET_ADDRESS_IPV4, /* sockaddr_in in 'socket_address_ipv4' */ EXPR_SOCKET_ADDRESS_IPV6, /* sockaddr_in6 in 'socket_address_ipv6' */ @@ -53,6 +54,7 @@ enum expression_t { #if defined(__FreeBSD__) EXPR_SF_HDTR, /* struct sf_hdtr for sendfile */ EXPR_TCP_FUNCTION_SET, /* struct tcp_function_set */ + EXPR_TCP_FASTOPEN, /* struct tcp_fastopen */ #endif EXPR_SCTP_RTOINFO, /* struct sctp_rtoinfo for SCTP_RTOINFO */ EXPR_SCTP_INITMSG, /* struct sctp_initmsg for SCTP_INITMSG */ @@ -127,6 +129,7 @@ struct expression { #if defined(__FreeBSD__) struct sf_hdtr_expr *sf_hdtr; struct tcp_function_set_expr *tcp_function_set; + struct tcp_fastopen_expr *tcp_fastopen; #endif struct sctp_rtoinfo_expr *sctp_rtoinfo; struct sctp_initmsg_expr *sctp_initmsg; @@ -252,6 +255,11 @@ struct tcp_function_set_expr { struct expression *function_set_name; struct expression *pcbcnt; }; + +struct tcp_fastopen_expr { + struct expression *enable; + struct expression *psk; +}; #endif /* Parse tree for a sctp_rtoinfo struct in a [gs]etsockopt syscall. */ -- GitLab