Skip to content

libquic: serialize setsockopt() with handshake sendmsg steps - #64

Open
lxin wants to merge 1 commit into
mainfrom
op_sockopt
Open

libquic: serialize setsockopt() with handshake sendmsg steps#64
lxin wants to merge 1 commit into
mainfrom
op_sockopt

Conversation

@lxin

@lxin lxin commented Mar 4, 2026

Copy link
Copy Markdown
Owner

Handshake messages and QUIC_SOCKOPT_CRYPTO_SECRET were previously queued together and processed while handling a received message. However, installing the application RX secret can immediately trigger application-level frames in the kernel (e.g. NEW_CONNECTION_ID, NEW_TOKEN, HANDSHAKE_DONE).

Because setsockopt() was not explicitly serialized with sendmsg(), those application frames could be emitted before all pending handshake CRYPTO frames were transmitted, violating the required ordering that handshake messages precede any application-level frames.

Introduce QUIC_HANDSHAKE_STEP_OP_SOCKOPT and treat setsockopt() operations as explicit handshake steps. This ensures:

  • setsockopt() is ordered relative to sendmsg() operations
  • all handshake CRYPTO frames are transmitted before installing the application RX secret
  • kernel-triggered application frames cannot overtake handshake data

The handshake engine now serializes all externally visible side effects (sendmsg, recvmsg, setsockopt), guaranteeing correct QUIC packet ordering and integrating setsockopt() into the handshake event loop.

Update the man page to document the new step type.

@lxin

lxin commented Mar 4, 2026

Copy link
Copy Markdown
Owner Author

@metze-samba Please help review this change whenever you're available.

Thanks!

@metze-samba

Copy link
Copy Markdown
Contributor

Ok, this is just a userspace change in order to force the correct order of syscalls, because there were possible
race conditions in the order of syscalls. But the content of the syscalls => the kernel ABI is still unchanged.

Is that assumption correct?

I'll port that change to samba in order to do some testing with it.

@metze-samba

Copy link
Copy Markdown
Contributor

While integrating it into samba I noticed that quic_handshake_step_sockopt doesn't have
'int level', can you add that, it should have everything explicitly that the setsockopt() syscall takes
no implicit SOL_QUIC.

I guess for now this can be set hard coded to SOL_QUIC in quic_prepare_sockopt_step().

What I don't really understand yet is this:

struct quic_smsg *last; seems to be unused.

quic_smsg_append_list(ctx, smsg, ctx->completed); for rx_secret

why is ctx->completed passed as 'uint8_t send'

And the logic around this 'send' in quic_smsg_append_list() is not
clear.

Is 'send' supposed to indicate that it's a sendmsg? If so we can already check this
by if (!smsg->optname).

@lxin

lxin commented Mar 5, 2026

Copy link
Copy Markdown
Owner Author

Ok, this is just a userspace change in order to force the correct order of syscalls, because there were possible race conditions in the order of syscalls. But the content of the syscalls => the kernel ABI is still unchanged.

Is that assumption correct?

right, no kernel ABI is affected.

While integrating it into samba I noticed that quic_handshake_step_sockopt doesn't have 'int level', can you add that, it should have everything explicitly that the setsockopt() syscall takes no implicit SOL_QUIC.

Sure, I can add it.

I guess for now this can be set hard coded to SOL_QUIC in quic_prepare_sockopt_step().

What I don't really understand yet is this:

struct quic_smsg *last; seems to be unused.

quic_smsg_append_list(ctx, smsg, ctx->completed); for rx_secret

why is ctx->completed passed as 'uint8_t send'

And the logic around this 'send' in quic_smsg_append_list() is not clear.

Is 'send' supposed to indicate that it's a sendmsg? If so we can already check this by if (!smsg->optname).

@metze-samba

'send' is used to indicate this step will trigger data sending, it doesn't have to be sendmsg step. The APP TX secret setting will also trigger data sending in kernel.

ctx->completed happens to be set in quic_set_secret() when APP TX secret setting sockopt step is added, then I reuse it, which seems not a nice idea.

'last' points to last node of the list, used to link the new node into the list more efficiently. send_last points to the last node (that was added with send = 1) of the list, used to set MSG_MORE flag for send_last if the new node to add will trigger data sending.

I will add some comments for these.

Please also check if there's other better way to implement this sockopt step.

Thanks.

@lxin

lxin commented Mar 5, 2026

Copy link
Copy Markdown
Owner Author

Updated.

Note without this patch, the packet series are:

    1   0.000000    127.0.0.1 → 127.0.0.1    QUIC 1242 Initial, DCID=813552003d7abf17, SCID=1e94d01fa75095c4, PKN: 0, CRYPTO, PADDING
    2   0.015292    127.0.0.1 → 127.0.0.1    QUIC 1242 Initial, DCID=1e94d01fa75095c4, SCID=c60d00cfa36088df, PKN: 0, ACK, CRYPTO, PADDING
    3   0.015306    127.0.0.1 → 127.0.0.1    QUIC 1466 Handshake, DCID=1e94d01fa75095c4, SCID=c60d00cfa36088df, PKN: 0, CRYPTO, CRYPTO, CRYPTO, CRYPTO
    4   0.015928    127.0.0.1 → 127.0.0.1    QUIC 1492 Protected Payload (KP0), DCID=c60d00cfa36088df, PKN: 0, NCI, NCI, NCI, NCI, NCI, NCI
    5   0.015952    127.0.0.1 → 127.0.0.1    QUIC 128 Handshake, DCID=c60d00cfa36088df, SCID=1e94d01fa75095c4, PKN: 1, CRYPTO
    6   0.016029    127.0.0.1 → 127.0.0.1    QUIC 366 Protected Payload (KP0), DCID=1e94d01fa75095c4, PKN: 0, ACK_ECN, NT, DONE, NCI, NCI, NCI, NCI, NCI, NCI

With this patch:

    1   0.000000    127.0.0.1 → 127.0.0.1    QUIC 1242 Initial, DCID=3af31b1e9c7ac2fd, SCID=d5672454051ed51b, PKN: 0, CRYPTO, PADDING
    2   0.015224    127.0.0.1 → 127.0.0.1    QUIC 1242 Initial, DCID=d5672454051ed51b, SCID=e5fdb93beede8d9e, PKN: 0, ACK, CRYPTO, PADDING
    3   0.015238    127.0.0.1 → 127.0.0.1    QUIC 1466 Handshake, DCID=d5672454051ed51b, SCID=e5fdb93beede8d9e, PKN: 0, CRYPTO, CRYPTO, CRYPTO, CRYPTO
    4   0.015868    127.0.0.1 → 127.0.0.1    QUIC 1334 Handshake, DCID=e5fdb93beede8d9e, SCID=d5672454051ed51b, PKN: 0, ACK, CRYPTO
    5   0.015884    127.0.0.1 → 127.0.0.1    QUIC 239 Protected Payload (KP0), DCID=e5fdb93beede8d9e, PKN: 0, NCI, NCI, NCI, NCI, NCI, NCI
    6   0.015958    127.0.0.1 → 127.0.0.1    QUIC 363 Protected Payload (KP0), DCID=d5672454051ed51b, PKN: 0, ACK_ECN, NT, DONE, NCI, NCI, NCI, NCI, NCI, NCI

Thanks.

@metze-samba

Copy link
Copy Markdown
Contributor

With the new patch it's a bit confusing that 'int level' is not used either for SOL_QUIC or the crypto level,
but that's ok for me.

But it's still confusing that we set MSG_MORE in these cases:

  1. the last one was a SENDMSG, but the new one is setsockopt
  2. the last one was setsockopt, but the new one is sendmsg

I did some tests with the first patch and it failed for some reason,
then I noticed that it's even broken without that patch.

So something broke between 846dddb
(the version I'm using in samba) and 092e820.

In the kernel I applied the v9 patchset (or something between v8 and v9),
see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01
for the exact patches.

Applying these (the top3) to Samba breaks it:
https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4

Even the first one alone

@lxin

lxin commented Mar 5, 2026

Copy link
Copy Markdown
Owner Author

With the new patch it's a bit confusing that 'int level' is not used either for SOL_QUIC or the crypto level, but that's ok for me.

But it's still confusing that we set MSG_MORE in these cases:

if SOCKOPT is added with 'send' = 1, setsockopt() will trigger kernel to send some control msgs like NCI frames. if SOCKOPT is added with 'send' = 0, it won't to the 'if (send)' branch to change the last one (SENDMSG) .

So assuming the SOCKOPT you mentioned below are all added 'send' = 1,

  1. the last one was a SENDMSG, but the new one is setsockopt

The last one SENDMSG will send msg A with MSG_MORE, and the msg A in kernel will NOT scheduled to send due to the MSG_MORE flags.

Then the new one SOCKOPT will call setsockopt(), which triggers kernel to send a msg B, then the kernel will try to bundle the A and B into one packet and send it out.

  1. the last one was setsockopt, but the new one is sendmsg

The last one SOCKOPT will ignore the MSG_MORE (although the flags is set), and trigger kernel to send a msg anyway, there will NOT be msg bundle with the msg sent in the new one SENDMSG.

We actually think the SOCKOPT with 'send' = 1 as the last step of handshake, and the new one SENDMSG will be application data(not handshake message) after handshake is completed, so I didn't expose a field in struct quic_crypto_secret to allow users to hold the NCI frames msg in kernel for the bundle, although this may be supported in the future.

Thanks.

@lxin

lxin commented Mar 5, 2026

Copy link
Copy Markdown
Owner Author

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.

So something broke between 846dddb (the version I'm using in samba) and 092e820.

In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.

Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4

Even the first one alone

Could be this one missing in the v9 patchset:

00d7b2b

I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.

It could break, if you're using the new uapi quic.h, but the kernel part is old.

It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Thanks.

@metze-samba

Copy link
Copy Markdown
Contributor

With the new patch it's a bit confusing that 'int level' is not used either for SOL_QUIC or the crypto level, but that's ok for me.
But it's still confusing that we set MSG_MORE in these cases:

if SOCKOPT is added with 'send' = 1, setsockopt() will trigger kernel to send some control msgs like NCI frames. if SOCKOPT is added with 'send' = 0, it won't to the 'if (send)' branch to change the last one (SENDMSG) .

So assuming the SOCKOPT you mentioned below are all added 'send' = 1,

  1. the last one was a SENDMSG, but the new one is setsockopt

The last one SENDMSG will send msg A with MSG_MORE, and the msg A in kernel will NOT scheduled to send due to the MSG_MORE flags.

Then the new one SOCKOPT will call setsockopt(), which triggers kernel to send a msg B, then the kernel will try to bundle the A and B into one packet and send it out.

  1. the last one was setsockopt, but the new one is sendmsg

The last one SOCKOPT will ignore the MSG_MORE (although the flags is set), and trigger kernel to send a msg anyway, there will NOT be msg bundle with the msg sent in the new one SENDMSG.

We actually think the SOCKOPT with 'send' = 1 as the last step of handshake, and the new one SENDMSG will be application data(not handshake message) after handshake is completed, so I didn't expose a field in struct quic_crypto_secret to allow users to hold the NCI frames msg in kernel for the bundle, although this may be supported in the future.

Maybe calling it 'int flush' or 'int eor' would be better to understand.

@metze-samba

Copy link
Copy Markdown
Contributor

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:

00d7b2b

I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.

It could break, if you're using the new uapi quic.h, but the kernel part is old.

It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.

In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:
00d7b2b
I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.
It could break, if you're using the new uapi quic.h, but the kernel part is old.
It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.

In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

Yes, try git revert 9a992ac, and it will delete the reserved field added in struct quic_handshake_info.

is your code using /usr/include/linux/quic.h? Make sure the the same reserved field doesn't exists, although it shouldn't be there if it was installed from kernel tree.

Let me know if it doesn't work.

Thanks.

@metze-samba

Copy link
Copy Markdown
Contributor

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:
00d7b2b
I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.
It could break, if you're using the new uapi quic.h, but the kernel part is old.
It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.
In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

Yes, try git revert 9a992ac, and it will delete the reserved field added in struct quic_handshake_info.

And it that doesn't help I'll also try to revert fad9bfd.

is your code using /usr/include/linux/quic.h? Make sure the the same reserved field doesn't exists, although it shouldn't be there if it was installed from kernel tree.

No, it's using the custom one.

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:
00d7b2b
I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.
It could break, if you're using the new uapi quic.h, but the kernel part is old.
It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.
In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

Yes, try git revert 9a992ac, and it will delete the reserved field added in struct quic_handshake_info.

And it that doesn't help I'll also try to revert fad9bfd.

Interesting, does the make check in the quic repro work on your env after reverting 9a992ac ?

@metze-samba

Copy link
Copy Markdown
Contributor

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:
00d7b2b
I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.
It could break, if you're using the new uapi quic.h, but the kernel part is old.
It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.
In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

Yes, try git revert 9a992ac, and it will delete the reserved field added in struct quic_handshake_info.

And it that doesn't help I'll also try to revert fad9bfd.

Interesting, does the make check in the quic repro work on your env after reverting 9a992ac ?

I guess it can't even build

But removing it from quic_handshake_info in the Samba copy fixes the problem.

But it means that new userspace would not work with old kernel, correct?
Maybe we want to change cmsg->cmsg_len = CMSG_LEN(sizeof(*info));
to also use offsetof... and only specify what's needed until it's really used

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:
00d7b2b
I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.
It could break, if you're using the new uapi quic.h, but the kernel part is old.
It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.
In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

Yes, try git revert 9a992ac, and it will delete the reserved field added in struct quic_handshake_info.

And it that doesn't help I'll also try to revert fad9bfd.

Interesting, does the make check in the quic repro work on your env after reverting 9a992ac ?

I guess it can't even build

But removing it from quic_handshake_info in the Samba copy fixes the problem.

But it means that new userspace would not work with old kernel, correct? Maybe we want to change cmsg->cmsg_len = CMSG_LEN(sizeof(*info)); to also use offsetof... and only specify what's needed until it's really used

Yes, I only considered the new kernel with the old userspace.
Using offsetof in libquic could be a great idea at this moment, can you give it try on your env and submit a PR?

Sorry for this inconvenience.

@metze-samba

Copy link
Copy Markdown
Contributor

I did some tests with the first patch and it failed for some reason, then I noticed that it's even broken without that patch.
So something broke between 846dddb (the version I'm using in samba) and 092e820.
In the kernel I applied the v9 patchset (or something between v8 and v9), see https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/unstable-7.0.0-rc1-z-metze-perf.01 for the exact patches.
Applying these (the top3) to Samba breaks it: https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=4dc56459998148264712d88b4c971b9e604037c4
Even the first one alone

Could be this one missing in the v9 patchset:
00d7b2b
I add some reserved fields for the future extension in some structs, and work around it in kernel with this commit.
It could break, if you're using the new uapi quic.h, but the kernel part is old.
It should be fixed by using the v10 quic from https://github.com/lxin/net-next/commits/quic/

Ok, but will take a bit of time before I'm able to test it, maybe one or two weeks.
In the meantime is there a userspace patch I can revert for now, so that I can test the setsockopt changes with the v9 kernel module?

Yes, try git revert 9a992ac, and it will delete the reserved field added in struct quic_handshake_info.

And it that doesn't help I'll also try to revert fad9bfd.

Interesting, does the make check in the quic repro work on your env after reverting 9a992ac ?

I guess it can't even build
But removing it from quic_handshake_info in the Samba copy fixes the problem.
But it means that new userspace would not work with old kernel, correct? Maybe we want to change cmsg->cmsg_len = CMSG_LEN(sizeof(*info)); to also use offsetof... and only specify what's needed until it's really used

Yes, I only considered the new kernel with the old userspace. Using offsetof in libquic could be a great idea at this moment, can you give it try on your env and submit a PR?

This fixes it too:

diff --git a/third_party/quic/libquic/handshake.c b/third_party/quic/libquic/handshake.c
index 047585e5a088..3742dfc52c38 100644
--- a/third_party/quic/libquic/handshake.c
+++ b/third_party/quic/libquic/handshake.c
@@ -248,7 +248,7 @@ static struct quic_smsg *quic_smsg_create(int level, int optname,
        cmsg = CMSG_FIRSTHDR(&smsg->msg);
        cmsg->cmsg_level = SOL_QUIC;
        cmsg->cmsg_type = QUIC_HANDSHAKE_INFO;
-       cmsg->cmsg_len = CMSG_LEN(sizeof(*info));
+       cmsg->cmsg_len = CMSG_LEN(offsetof(struct quic_handshake_info, reserved));
 
        info = (struct quic_handshake_info *)CMSG_DATA(cmsg);
        info->crypto_level = level;

Please just do the commit with you as owner and handle all the related
work.

Also note that using offsetof(struct quic_stream_info, reserved)
would be wrong, as sizeof(struct quic_stream_info) was already
16 before, as there was no __packed, so old kernels already check
for 16.

@metze-samba

Copy link
Copy Markdown
Contributor

I noticed that 00d7b2b
uses offsetof(struct quic_stream_info, reserved), I'm not sure this is correct, it seems to be ok
for quic_msghdr_parse(), but I think it might be better to revert to sizeof(struct quic_stream_info)
in both cases

@metze-samba

Copy link
Copy Markdown
Contributor

Maybe a bunch of checks like this: BUILD_BUG_ON(sizeof(struct io_uring_sqe) != 64); in io_uring_init()
would be good to have for the uapi related structures.

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

I noticed that 00d7b2b uses offsetof(struct quic_stream_info, reserved), I'm not sure this is correct, it seems to be ok for quic_msghdr_parse(), but I think it might be better to revert to sizeof(struct quic_stream_info) in both cases

On 32 bits systems, sizeof(struct quic_stream_info) is 12 bytes, not 16 bytes.

It was added to fix a failure when older userspace interacts with a newer kernel on 32 bits systems.

Just note that these offsetofs are temporary work around, they will all be reverted when I post the 2nd patchset to upstream, before that I check and make sure all users to get quic.h to the latest version.

Now I think it seems not a good idea to apply the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO", as after the revert, the userspace code need sto be reverted again, otherwise, the older userpsace can not interacts with the new kernel again.

Is that okay to you that I remove the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO" that I just applied? And on your side, update the kernel part to v10 or add a temporary fix on userspace for the current test?

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

Maybe calling it 'int flush' or 'int eor' would be better to understand.

Updated to int flush, please check.

Thanks.

@metze-samba

Copy link
Copy Markdown
Contributor

I noticed that 00d7b2b uses offsetof(struct quic_stream_info, reserved), I'm not sure this is correct, it seems to be ok for quic_msghdr_parse(), but I think it might be better to revert to sizeof(struct quic_stream_info) in both cases

On 32 bits systems, sizeof(struct quic_stream_info) is 12 bytes, not 16 bytes.

It was added to fix a failure when older userspace interacts with a newer kernel on 32 bits systems.

Just note that these offsetofs are temporary work around, they will all be reverted when I post the 2nd patchset to upstream, before that I check and make sure all users to get quic.h to the latest version.

Now I think it seems not a good idea to apply the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO", as after the revert, the userspace code need sto be reverted again, otherwise, the older userpsace can not interacts with the new kernel again.

Is that okay to you that I remove the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO" that I just applied? And on your side, update the kernel part to v10 or add a temporary fix on userspace for the current test?

I'd prefer to keep it, I will mean any possible existing installation will break.

@metze-samba

Copy link
Copy Markdown
Contributor

I noticed that 00d7b2b uses offsetof(struct quic_stream_info, reserved), I'm not sure this is correct, it seems to be ok for quic_msghdr_parse(), but I think it might be better to revert to sizeof(struct quic_stream_info) in both cases

On 32 bits systems, sizeof(struct quic_stream_info) is 12 bytes, not 16 bytes.
It was added to fix a failure when older userspace interacts with a newer kernel on 32 bits systems.
Just note that these offsetofs are temporary work around, they will all be reverted when I post the 2nd patchset to upstream, before that I check and make sure all users to get quic.h to the latest version.
Now I think it seems not a good idea to apply the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO", as after the revert, the userspace code need sto be reverted again, otherwise, the older userpsace can not interacts with the new kernel again.
Is that okay to you that I remove the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO" that I just applied? And on your side, update the kernel part to v10 or add a temporary fix on userspace for the current test?

I'd prefer to keep it, I will mean any possible existing installation will break.

What's the problem with 2d7f826 ?

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

I'd prefer to keep it, I will mean any possible existing installation will break.

What's the problem with 2d7f826 ?

The existing installation is fine if they don't rebuild the userspace code with the new quic.h fomr quic repo while using the QUIC <= v9.

If we use that commit now, It will be really a pain after the QUIC get merged into kernel and we want to extend the quic_handshake_info with the reserved field in the future, because all old userspace will break after the extending. My plan was to expose this issue when the upstream kernel doesn't support QUIC yet.

This is a hard one, and I need to think more about it.

Thanks.

@metze-samba

Copy link
Copy Markdown
Contributor

On 32 bits systems, sizeof(struct quic_stream_info) is 12 bytes, not 16 bytes.
It was added to fix a failure when older userspace interacts with a newer kernel on 32 bits systems.
Just note that these offsetofs are temporary work around, they will all be reverted when I post the 2nd patchset to upstream, before that I check and make sure all users to get quic.h to the latest version.
Now I think it seems not a good idea to apply the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO", as after the revert, the userspace code need sto be reverted again, otherwise, the older userpsace can not interacts with the new kernel again.
Is that okay to you that I remove the commit "libquic: adjust cmsg_len for QUIC_HANDSHAKE_INFO" that I just applied? And on your side, update the kernel part to v10 or add a temporary fix on userspace for the current test?

I'd prefer to keep it, I will mean any possible existing installation will break.

The existing installation is fine if they don't rebuild the userspace code with the new quic.h fomr quic repo while using the QUIC <= v9.

It means I won't update Samba with the setsockopt stuff, as it means it needs the lastest kernel module
for no reason.

If we use that commit now, It will be really a pain after the QUIC get merged into kernel and we want to extend the quic_handshake_info with the reserved field in the future. My plan was to expose this issue when the upstream kernel doesn't support QUIC yet.

When the reserved stuff will be used by new userspace it expects the kernel to support it too
or it needs a way to autodetect the kernel version, so there's a need to have fallback logic
in userspace. I think for that we should use copy_struct_from_user() or at least the error logic it uses.
So that an old kernel without the new feature returns -E2BIG if an unknown feature is used
(the reserved bytes are there and any bit is non-zero). And to handle old client also catch -EINVAL.

Maybe it would be better to have a getsockopt() call to ask the kernel for features
and use that maybe with quic_config.

I also think it might be useful for quic_config and quic_transport_param to be handled with
copy_struct_from_sockptr() and copy_struct_to_sockptr().

I have a patch for copy_struct_to_sockptr() here:
https://git.samba.org/?p=metze/linux/wip.git;a=commitdiff;h=8a342d2b491aa6d420dbc161d68de1f87e61ddbf
I haven't posted it yet, I'll do that once my IPPROTO_SMBDIRECT gets ready to be posted.

@metze-samba

Copy link
Copy Markdown
Contributor

What I want to say is, the problem of supporting growing structures for new features
is already solved with copy_struct_{from,to}*.

@metze-samba

Copy link
Copy Markdown
Contributor

I have a patch for copy_struct_to_sockptr() here: https://git.samba.org/?p=metze/linux/wip.git;a=commitdiff;h=8a342d2b491aa6d420dbc161d68de1f87e61ddbf I haven't posted it yet, I'll do that once my IPPROTO_SMBDIRECT gets ready to be posted.

Feel free to use it, but please try to fix typos and missing words in the commit message.

@lxin

lxin commented Mar 6, 2026

Copy link
Copy Markdown
Owner Author

The existing installation is fine if they don't rebuild the userspace code with the new quic.h fomr quic repo while using the QUIC <= v9.

It means I won't update Samba with the setsockopt stuff, as it means it needs the lastest kernel module for no reason.

That's indeed a problem.

If we use that commit now, It will be really a pain after the QUIC get merged into kernel and we want to extend the quic_handshake_info with the reserved field in the future. My plan was to expose this issue when the upstream kernel doesn't support QUIC yet.

When the reserved stuff will be used by new userspace it expects the kernel to support it too or it needs a way to autodetect the kernel version, so there's a need to have fallback logic in userspace. I think for that we should use copy_struct_from_user() or at least the error logic it uses. So that an old kernel without the new feature returns -E2BIG if an unknown feature is used (the reserved bytes are there and any bit is non-zero). And to handle old client also catch -EINVAL.

Maybe it would be better to have a getsockopt() call to ask the kernel for features and use that maybe with quic_config.

I also think it might be useful for quic_config and quic_transport_param to be handled with copy_struct_from_sockptr() and copy_struct_to_sockptr().

OK, this should work. I've brought 2d7f826 back to the repo.

I have a patch for copy_struct_to_sockptr() here: https://git.samba.org/?p=metze/linux/wip.git;a=commitdiff;h=8a342d2b491aa6d420dbc161d68de1f87e61ddbf I haven't posted it yet, I'll do that once my IPPROTO_SMBDIRECT gets ready to be posted.

Cool!

@lxin
lxin force-pushed the op_sockopt branch 2 times, most recently from c16c040 to 8ef560c Compare March 7, 2026 23:52
@metze-samba

Copy link
Copy Markdown
Contributor

More more thing, I think QUIC_HANDSHAKE_STEP_OP_SOCKOPT should be QUIC_HANDSHAKE_STEP_OP_SETSOCKOPT, and s_sockopt; s_setsockopt;

In future we may need a GETSOCKOPT...

@lxin

lxin commented Mar 10, 2026

Copy link
Copy Markdown
Owner Author

More more thing, I think QUIC_HANDSHAKE_STEP_OP_SOCKOPT should be QUIC_HANDSHAKE_STEP_OP_SETSOCKOPT, and s_sockopt; s_setsockopt;

updated.

@metze-samba

Copy link
Copy Markdown
Contributor

The Samba selftests don't work with this using quic_ko_wrapper.
I need to find some time to debug that, then I'll also check if it still works against windows.

@lxin

lxin commented Mar 10, 2026

Copy link
Copy Markdown
Owner Author

The Samba selftests don't work with this using quic_ko_wrapper.

You mean it doesn't work with SETSOCKOPT step, but it worked without SETSOCKOPT step?

I need to find some time to debug that, then I'll also check if it still works against windows.

Sure, leave me a message if anything needed.

BTW, is it easy to deploy and run the Samba selftests? I'm think to add a github workflow in this repo to trigger it whenever a commit is submitted.

Thanks.

@lxin

lxin commented Mar 11, 2026

Copy link
Copy Markdown
Owner Author

@metze-samba FYI, an issue was just reported in #66, which caused the failures in the interop testing with neqo userland QUIC, I just revert the buggy commit. No sure if this may fix the samba selftests failure. (Note the issue only existed on the QUIC repo kernel modules, NOT upstream v9 or v10 patches).

Handshake messages and QUIC_SOCKOPT_CRYPTO_SECRET were previously queued
together and processed while handling a received message.  However,
installing the application RX secret can immediately trigger
application-level frames in the kernel (e.g. NEW_CONNECTION_ID, NEW_TOKEN,
HANDSHAKE_DONE).

Because setsockopt() was not explicitly serialized with sendmsg(), those
application frames could be emitted before all pending handshake CRYPTO
frames were transmitted, violating the required ordering that handshake
messages precede any application-level frames.

Introduce QUIC_HANDSHAKE_STEP_OP_SETSOCKOPT and treat setsockopt()
operations as explicit handshake steps. This ensures:

  - setsockopt() is ordered relative to sendmsg() operations
  - all handshake CRYPTO frames are transmitted before installing the
    application RX secret
  - kernel-triggered application frames cannot overtake handshake data

The handshake engine now serializes all externally visible side effects
(sendmsg, recvmsg, setsockopt), guaranteeing correct QUIC packet
ordering and integrating setsockopt() into the handshake event loop.

Update the man page to document the new step type.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants