From: Sabrina Dubroca <sd@queasysnail.net>
To: kuba@kernel.org, Rishikesh Jethwani <rjethwani@purestorage.com>
Cc: netdev@vger.kernel.org, saeedm@nvidia.com, tariqt@nvidia.com,
mbloch@nvidia.com, borisp@nvidia.com, john.fastabend@gmail.com,
davem@davemloft.net, pabeni@redhat.com, edumazet@google.com,
leon@kernel.org
Subject: Re: [PATCH v12 6/6] selftests: net: add TLS hardware offload test
Date: Wed, 8 Apr 2026 18:45:53 +0200 [thread overview]
Message-ID: <adaGQRUUNbXWXNgP@krikkit> (raw)
In-Reply-To: <20260402235511.664801-7-rjethwani@purestorage.com>
@Jakub [top-posting so you don't have to scroll through the rest of my
comments to find some global questions about this patch]
tools/testing/selftests/drivers/net/README.rst mentions "Local
host is the DUT", but this test does rekeys on both sides and sends a
bit of traffic back and forth. Is that acceptable?
Another thought: is there a "standard" for stdout vs stderr, as well as
verbosity of "test progress"/"debug" type messages ("sent
keyupdate"/"received keyupdate"/"server listening"/"setup complete"
etc) for those test programs? Any expectation for a --{debug,verbose}
option to only display all this stuff on request?
Output for 1 test:
-------- 8< --------
TLS Version: TLS 1.3
Cipher: AES-GCM-128
Buffer size: 16384
Connecting to 192.168.13.1:4433...
Connected!
Installing TLS_TX AES-GCM-128 gen 0...
TLS_TX AES-GCM-128 gen 0 installed
Installing TLS_RX AES-GCM-128 gen 0...
TLS_RX AES-GCM-128 gen 0 installed
TLS setup complete.
Sending 100 messages of 16384 bytes...
Sent 16384 bytes (iteration 1)
Received echo 16384 bytes (ok)
[...repeated]
Sent 16384 bytes (iteration 100)
Received echo 16384 bytes (ok)
-------- 8< --------
With some rekeys I get 300L of output on each side.
If not, I guess we can fall back to what makes the most sense for
NIPA?
2026-04-02, 17:55:11 -0600, Rishikesh Jethwani wrote:
> diff --git a/tools/testing/selftests/drivers/net/hw/tls_hw_offload.c b/tools/testing/selftests/drivers/net/hw/tls_hw_offload.c
> new file mode 100644
> index 000000000000..788891890ec8
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/net/hw/tls_hw_offload.c
I think it would make sense to add the new files to the
"NETWORKING [TLS]" entry in MAINTAINERS. We already have the existing
selftest listed.
[...]
> +#define TEST_ITERATIONS 100
> +#define MAX_REKEYS 99
Making TEST_ITERATIONS a test argument would allow a test that lasts
more than half a second. Then MAX_REKEYS can be removed and the
argument validation switched to num_rekeys < num_iterations. (doing
rekeys without a send() in between [other than the send_keyupdate]
should be fine, but it makes the logic for "do we send a rekey and/or
application_data this round?" more complex, so let's keep the check on
num_rekeys)
In general, this test is a good start, but it doesn't cover enough
(see my reply to 5/6). How did you test the "unacked records" part of
the rekey patch? It's the most complex part of the series.
[...]
> +static void derive_key_fields(unsigned char *key, int key_size,
> + unsigned char *iv, int iv_size,
> + unsigned char *salt, int salt_size,
> + unsigned char *rec_seq, int rec_seq_size,
> + int generation)
> +{
> + unsigned char pattern;
> + int i;
> +
> + if (generation == 0)
> + return;
> +
> + pattern = (unsigned char)((generation * 0x1B) ^ 0x63);
> + for (i = 0; i < key_size; i++) {
> + key[i] ^= pattern;
> + pattern = (pattern << 1) | (pattern >> 7);
> + }
> +
> + pattern = (unsigned char)((generation * 0x2D) ^ 0x7C);
> + for (i = 0; i < iv_size; i++) {
> + iv[i] ^= pattern;
> + pattern = (pattern << 1) | (pattern >> 7);
> + }
> +
> + for (i = 0; i < salt_size; i++)
> + salt[i] ^= (unsigned char)(generation & 0xFF);
> +
> + memset(rec_seq, 0, rec_seq_size);
> +}
This isn't wrong (so I'm not requesting to change it), but it seems
way overkill for "we want to fill tls12_crypto_info_aes_gcm_* with
some predictable data based only on key_generation".
> +/* Send TLS 1.3 KeyUpdate handshake message */
> +static int send_tls_key_update(int fd, int request_update)
> +{
> + char cmsg_buf[CMSG_SPACE(sizeof(unsigned char))];
> + unsigned char key_update_msg[5];
> + struct msghdr msg = {0};
> + struct cmsghdr *cmsg;
> + struct iovec iov;
> +
> + key_update_msg[0] = TLS_HANDSHAKE_KEY_UPDATE;
> + key_update_msg[1] = 0;
> + key_update_msg[2] = 0;
> + key_update_msg[3] = 1;
> + key_update_msg[4] = request_update ? KEY_UPDATE_REQUESTED
> + : KEY_UPDATE_NOT_REQUESTED;
I'm still really not convinced we need to bother with things that
would only affect a "proper" userspace.
[...]
> +static int validate_keyupdate(const char *buf, int len)
> +{
> + if (len != 5) {
> + printf("KeyUpdate: expected 5 bytes, got %d\n", len);
> + return -1;
> + }
> +
> + if ((unsigned char)buf[0] != TLS_HANDSHAKE_KEY_UPDATE) {
> + printf("Expected KeyUpdate (0x%02x), got 0x%02x\n",
> + TLS_HANDSHAKE_KEY_UPDATE, (unsigned char)buf[0]);
> + return -1;
> + }
> +
> + if (buf[1] != 0 || buf[2] != 0 || buf[3] != 1) {
> + printf("KeyUpdate: bad length field %02x%02x%02x\n",
> + (unsigned char)buf[1], (unsigned char)buf[2],
> + (unsigned char)buf[3]);
> + return -1;
> + }
And same here.
> + if ((unsigned char)buf[4] != KEY_UPDATE_NOT_REQUESTED &&
> + (unsigned char)buf[4] != KEY_UPDATE_REQUESTED) {
> + printf("KeyUpdate: invalid request_update value %u\n",
> + (unsigned char)buf[4]);
> + return -1;
> + }
And here.
What type of issue do you expect to identify by validating the
contents of the key update message that your test program is sending
to itself?
> + printf("Received TLS KeyUpdate (request_update=%u)\n",
> + (unsigned char)buf[4]);
> + return 0;
> +}
> +
...
> +static int do_client(void)
> +{
> + char *buf = NULL, *echo_buf = NULL;
> + int max_size, rekey_interval;
> + ssize_t echo_total, echo_n;
> + int csk = -1, ret, i, j;
> + struct sockaddr_in sa;
> + int test_result = -1;
> + int current_gen = 0;
> + int next_rekey_at;
> + ssize_t n;
> +
> + if (!server_ip) {
> + printf("ERROR: Client requires -s <ip> option\n");
> + return -1;
> + }
> +
> + max_size = random_size_max > 0 ? random_size_max : send_size;
> + if (max_size < MIN_BUF_SIZE)
> + max_size = MIN_BUF_SIZE;
> + buf = malloc(max_size);
> + echo_buf = malloc(max_size);
> + if (!buf || !echo_buf) {
> + printf("failed to allocate buffers\n");
> + goto out;
> + }
> +
> + csk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> + if (csk < 0) {
> + printf("failed to create socket: %s\n", strerror(errno));
Those failures (malloc, socket, connect, maybe also initial key setup)
could use a common prefix (maybe "SETUP ERROR") to differentate them
from "invalid arguments" and "actual test failure".
[...]
> + rekey_interval = TEST_ITERATIONS / (num_rekeys + 1);
> + if (rekey_interval < 1)
> + rekey_interval = 1;
nit: should never happen since num_rekeys < TEST_ITERATIONS
> + next_rekey_at = rekey_interval;
> +
> + for (i = 0; i < TEST_ITERATIONS; i++) {
nit: i itself is never used, only i+1, so iterating from 1 up to
i <= TEST_ITERATIONS would be a tiny bit more readable.
> + int this_size;
> +
> + if (random_size_max > 0)
> + this_size = (rand() % random_size_max) + 1;
> + else
> + this_size = send_size;
> +
> + for (j = 0; j < this_size; j++)
> + buf[j] = rand() & 0xFF;
> +
> + n = send(csk, buf, this_size, 0);
> + if (n != this_size) {
> + printf("FAIL: send failed: %s\n", strerror(errno));
The test failures messages in the client consistently use "FAIL:" as a
prefix...
[...]
> +static int do_server(void)
> +{
[...]
> + /* Main receive loop */
> + while (1) {
[...]
> + printf("recv failed: %s\n", strerror(errno));
[...]
> + printf("Failed to send KeyUpdate\n");
[...]
> + printf("Echo send failed: %s\n",
> + strerror(errno));
...but not in the server.
[...]
> +int main(int argc, char *argv[])
> +{
[...]
> + if (tls_version == TLS_1_2_VERSION && num_rekeys) {
> + printf("ERROR: TLS 1.2 does not support rekey\n");
> + return -1;
> + }
Maybe also a check to make setting random_size_max incompatible with
setting send_size. And probably at least a warning when client-only
options (server_ip, random_size, num_rekeys) are passed to the server
and will be ignored.
The "Client requires -s <ip> option" check would also fit better here,
with the rest of the options checking.
> diff --git a/tools/testing/selftests/drivers/net/hw/tls_hw_offload.py b/tools/testing/selftests/drivers/net/hw/tls_hw_offload.py
> new file mode 100755
> index 000000000000..66c5ddfd8125
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/net/hw/tls_hw_offload.py
[...]
> +def verify_tls_counters(stats_before, stats_after, expected_rekeys, is_server):
This is much cleaner now, thanks.
> +def run_tls_test(cfg, cipher="128", tls_version="1.3", rekey=0, buffer_size=None, random_max=None):
> + port = rand_port()
> + send_size = random_max or buffer_size
> +
> + server_args = f"{cfg.bin_remote} server -p {port} -c {cipher} -v {tls_version}"
These variables were called {server,client}_cmd in the previous
version, I wonder why you renamed them to something less accurate
(since it's actually the full command, not just the arguments).
> + if send_size:
> + server_args += f" -b {send_size}"
> +
> + client_args = (f"{cfg.bin_local} client -s {cfg.remote_addr_v['4']} "
> + f"-p {port} -c {cipher} -v {tls_version}")
> + if rekey:
> + client_args += f" -k {rekey}"
> + if random_max:
> + client_args += f" -r {random_max}"
> + elif send_size:
> + client_args += f" -b {send_size}"
nit: I find the use of send_size here (instead of directly
buffer_size) slightly confusing, since we just took care of
"random_max was set".
--
Sabrina
next prev parent reply other threads:[~2026-04-08 16:45 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-02 23:55 [PATCH net-next v12 0/6] tls: Add TLS 1.3 hardware offload support Rishikesh Jethwani
2026-04-02 23:55 ` [PATCH v12 1/6] net: tls: reject TLS 1.3 offload in chcr_ktls and nfp drivers Rishikesh Jethwani
2026-04-02 23:55 ` [PATCH v12 2/6] net/mlx5e: add TLS 1.3 hardware offload support Rishikesh Jethwani
2026-04-02 23:55 ` [PATCH v12 3/6] tls: " Rishikesh Jethwani
2026-04-02 23:55 ` [PATCH v12 4/6] tls: split tls_set_sw_offload into init and finalize stages Rishikesh Jethwani
2026-04-02 23:55 ` [PATCH v12 5/6] tls: add hardware offload key update support Rishikesh Jethwani
2026-04-06 20:59 ` Sabrina Dubroca
2026-04-02 23:55 ` [PATCH v12 6/6] selftests: net: add TLS hardware offload test Rishikesh Jethwani
2026-04-08 16:45 ` Sabrina Dubroca [this message]
2026-04-08 17:44 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=adaGQRUUNbXWXNgP@krikkit \
--to=sd@queasysnail.net \
--cc=borisp@nvidia.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=leon@kernel.org \
--cc=mbloch@nvidia.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rjethwani@purestorage.com \
--cc=saeedm@nvidia.com \
--cc=tariqt@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox