From 41845919c1b96faf65abd542f09885b76f0c883f Mon Sep 17 00:00:00 2001 From: Manu Bretelle Date: Tue, 27 Jun 2023 18:40:43 -0700 Subject: [PATCH] net-test: packetdrill: add support of tcp option wildcard "wscale *" Summary: In current script, we can either specify every tcp option of a packet, or use <...> for "any tcp options". This is not flexible enough, as some script may have requirements for some tcp options; while be flexible with other options. This patch tries to address this by adding wildcard for option wscale. Specifically, "wscale *" in the tcp option list means any wscale value. To mark a tcp option in the script as wildcard, we leverage the highest bit of tcp_option->kind, as TCPOPT_WILDCARD (0x80). tcp_option->kind of TCPOPT_WILDCARD | TCPOPT_WINDOW (0x83) means wscale option of any value. verify_outbound_live_tcp_options() is updated to be able to understand TCPOPT_WILDCARD when set on the script packet and with TCPOPT_WINDOW. Testing: Using a script that currently fail on my environment with wscale: ``` $ sudo ./packetdrill/run_all.py -S -v -L -l tcp/zerocopy/fastopen-client.pkt FAIL [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client.pkt (ipv4)] stdout: stderr: fastopen-client.pkt:17: error handling packet: bad value outbound TCP option 3 script packet: 0.000105 S 0:0(0) actual packet: 0.000095 S 0:0(0) win 65535 FAIL [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client.pkt (ipv6)] stdout: stderr: fastopen-client.pkt:17: error handling packet: bad value outbound TCP option 3 script packet: 0.000157 S 0:0(0) actual packet: 0.000145 S 0:0(0) win 65535 FAIL [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client.pkt (ipv4-mapped-v6)] stdout: stderr: fastopen-client.pkt:17: error handling packet: bad value outbound TCP option 3 script packet: 0.000118 S 0:0(0) actual packet: 0.000106 S 0:0(0) win 65535 Ran 3 tests: 0 passing, 3 failing, 0 timed out (2.69 sec): tcp/zerocopy/fastopen-client.pkt ``` Changed the wscale to wildcard: ``` $ diff -ruN tcp/zerocopy/fastopen-client.pkt tcp/zerocopy/fastopen-client-wscale-wildcard.pkt --- tcp/zerocopy/fastopen-client.pkt 2023-06-27 18:36:22.956369457 -0700 +++ tcp/zerocopy/fastopen-client-wscale-wildcard.pkt 2023-06-27 18:37:29.306312093 -0700 @@ -14,7 +14,7 @@ +0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 +0 sendto(3, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = -1 EINPROGRESS (Operation now in progress) - +0 > S 0:0(0) + +0 > S 0:0(0) +.01 < S. 123:123(0) ack 1 win 14600 +0 > . 1:1(0) ack 1 @@ -35,7 +35,7 @@ +0 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0 setsockopt(5, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 +0 sendto(5, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = 500 - +0 > S 0:500(500) + +0 > S 0:500(500) +.05 < S. 5678:5678(0) ack 501 win 14600 +0 > . 501:501(0) ack 1 ``` and confirmed the test now pass: ``` $ sudo ./packetdrill/run_all.py -S -v -L -l tcp/zerocopy/fastopen-client-wscale-wildcard.pkt OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client-wscale-wildcard.pkt (ipv4)] stdout: stderr: OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client-wscale-wildcard.pkt (ipv6)] stdout: stderr: OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client-wscale-wildcard.pkt (ipv4-mapped-v6)] stdout: stderr: Ran 3 tests: 3 passing, 0 failing, 0 timed out (7.91 sec): tcp/zerocopy/fastopen-client-wscale-wildcard.pkt ``` and also still work properly when the wscale is matching expectations: ``` $ diff -ruN tcp/zerocopy/fastopen-client.pkt tcp/zerocopy/fastopen-client-correct-wscale.pkt --- tcp/zerocopy/fastopen-client.pkt 2023-06-27 18:36:22.956369457 -0700 +++ tcp/zerocopy/fastopen-client-correct-wscale.pkt 2023-06-27 18:39:24.630212385 -0700 @@ -14,7 +14,7 @@ +0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 +0 sendto(3, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = -1 EINPROGRESS (Operation now in progress) - +0 > S 0:0(0) + +0 > S 0:0(0) +.01 < S. 123:123(0) ack 1 win 14600 +0 > . 1:1(0) ack 1 @@ -35,7 +35,7 @@ +0 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0 setsockopt(5, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 +0 sendto(5, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = 500 - +0 > S 0:500(500) + +0 > S 0:500(500) +.05 < S. 5678:5678(0) ack 501 win 14600 +0 > . 501:501(0) ack 1 ``` with ``` $ sudo ./packetdrill/run_all.py -S -v -L -l tcp/zerocopy/fastopen-client-correct-wscale.pkt OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client-correct-wscale.pkt (ipv4)] stdout: stderr: OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client-correct-wscale.pkt (ipv6)] stdout: stderr: OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/zerocopy/fastopen-client-correct-wscale.pkt (ipv4-mapped-v6)] stdout: stderr: Ran 3 tests: 3 passing, 0 failing, 0 timed out (8.16 sec): tcp/zerocopy/fastopen-client-correct-wscale.pkt ``` Also comfirmed that wscale wildcard would not cause and option which has 0x80 set to pass. For instance with: ``` $ diff -ruN tcp/fastopen/server/simple2.pkt tcp/fastopen/server/simple2-wscale.pkt --- tcp/fastopen/server/simple2.pkt 2023-06-27 17:28:58.547790456 -0700 +++ tcp/fastopen/server/simple2-wscale.pkt 2023-06-27 19:00:49.460036441 -0700 @@ -22,7 +22,7 @@ +0 < S 9873242:9873242(0) win 10000 // Test the cookie is as expected by encoding both IPs w/ key - +0 > S. 0:0(0) ack 9873243 + +0 > S. 0:0(0) ack 9873243 +.1 < . 1:1(0) ack 1 win 257 +0 accept(3, ..., ...) = 4 +0 close(4) = 0 @@ -38,8 +38,8 @@ +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 - +.05 < S 19124022:19125022(1000) win 10000 - +0 > S. 0:0(0) ack 19125023 + +.05 < S 19124022:19125022(1000) win 10000 + +0 > S. 0:0(0) ack 19125023 +0 accept(3, ..., ...) = 4 `/tmp/sysctl_restore_${PPID}.sh` ``` The test fails at handling Fast Open Experimental ``` simple2-wscale.pkt:25: error handling packet: bad value outbound TCP option 254 script packet: 0.000163 S. 0:0(0) ack 9873243 actual packet: 0.000159 S. 0:0(0) ack 9873243 win 65535 OK [/data/users/chantra/google-packetdrill/gtests/net/tcp/fastopen/server/simple2-wscale.pkt (ipv4-mapped-v6)] ``` Signed-off-by: Manu Bretelle --- gtests/net/packetdrill/parser.y | 4 ++++ gtests/net/packetdrill/run_packet.c | 9 +++++++-- gtests/net/packetdrill/tcp.h | 11 +++++++++++ gtests/net/packetdrill/tcp_options_iterator.c | 1 + gtests/net/packetdrill/tcp_options_to_string.c | 4 ++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index 08aff3ea..f01555c1 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -1282,6 +1282,10 @@ tcp_option } $$->data.window_scale.shift_count = $2; } +| WSCALE '*' { + $$ = tcp_option_new(TCPOPT_WINDOW | TCPOPT_WILDCARD, TCPOLEN_WINDOW); + $$->data.window_scale.shift_count = 0; +} | SACKOK { $$ = tcp_option_new(TCPOPT_SACK_PERMITTED, TCPOLEN_SACK_PERMITTED); diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index da0e6b67..f5a4f9be 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -1383,12 +1383,17 @@ static int verify_outbound_live_tcp_options( /* TCP options are expected to be a deterministic order. */ while (a_opt != NULL || s_opt != NULL) { if (a_opt == NULL || s_opt == NULL || - a_opt->kind != s_opt->kind) { + (a_opt->kind != s_opt->kind && + !(s_opt->kind == (TCPOPT_WILDCARD | TCPOPT_WINDOW) && + a_opt->kind == TCPOPT_WINDOW))) { asprintf(error, "bad outbound TCP options"); return STATUS_ERR; } - if (verify_outbound_tcp_option(state, actual_packet, + /* skip byte-to-byte comparison of wildcard option */ + if (s_opt->kind == (TCPOPT_WILDCARD | TCPOPT_WINDOW)) + ; + else if (verify_outbound_tcp_option(state, actual_packet, script_packet, a_opt, s_opt, error) != STATUS_OK) { return STATUS_ERR; diff --git a/gtests/net/packetdrill/tcp.h b/gtests/net/packetdrill/tcp.h index d95ba449..289929f5 100644 --- a/gtests/net/packetdrill/tcp.h +++ b/gtests/net/packetdrill/tcp.h @@ -110,6 +110,17 @@ #define TCP_MD5_DIGEST_LEN 16 /* bytes in RFC2385 TCP MD5 digest */ +/* + * To compare subset of options between script packet and actual packet, + * we use * for "option with any value". For example, "wscale *" in the + * script packet means wscale option of any value. + * + * TCPOPT_WILDCARD is used to mark a option in the script packet as + * "any value". A script packet of kind "TCPOPT_WINDOW | TCPOPT_WILDCARD" + * means "wscale option of any value". + */ +#define TCPOPT_WILDCARD 0x80 + /* A portable TCP header definition (Linux and *BSD use different names). */ struct tcp { __be16 src_port; diff --git a/gtests/net/packetdrill/tcp_options_iterator.c b/gtests/net/packetdrill/tcp_options_iterator.c index 6123387d..3f45924a 100644 --- a/gtests/net/packetdrill/tcp_options_iterator.c +++ b/gtests/net/packetdrill/tcp_options_iterator.c @@ -50,6 +50,7 @@ static int get_expected_tcp_option_length(u8 kind, u8 *expected_length, break; case TCPOPT_WINDOW: + case TCPOPT_WINDOW | TCPOPT_WILDCARD: *expected_length = TCPOLEN_WINDOW; break; diff --git a/gtests/net/packetdrill/tcp_options_to_string.c b/gtests/net/packetdrill/tcp_options_to_string.c index 09a52301..84287153 100644 --- a/gtests/net/packetdrill/tcp_options_to_string.c +++ b/gtests/net/packetdrill/tcp_options_to_string.c @@ -106,6 +106,10 @@ int tcp_options_to_string(struct packet *packet, option->data.window_scale.shift_count); break; + case TCPOPT_WINDOW | TCPOPT_WILDCARD: + fprintf(s, "wscale *"); + break; + case TCPOPT_SACK_PERMITTED: fputs("sackOK", s); break;