axboe / liburing

Library providing helpers for the Linux kernel io_uring support
MIT License
2.72k stars 393 forks source link

[Feature request] Please consider adding DNS, time and Crypto opcodes #1116

Closed espoal closed 3 months ago

espoal commented 3 months ago

io_uring is designed also for high performance networking applications, and DNS and crypto are fundamental part of networking applications, especially modern ones, hence I think we should add some opcodes to consume DNS and crypto sources asynchronously.

Lately I've been playing with a QUIC implementation on top of io_uring, and currently there are only two parts of my code that are blocking:

I see entropy gathering can be easily solved by multiple syscalls (getrandom,getentropy, geturandom, ...), while for DNS we could use something like getaddrinfo.

Update:

To fully support modern protocol like QUIC we would also need an opcode for the time syscall

@axboe wdyt?

ammarfaizi2 commented 3 months ago

Hi @espoal,

While I appreciate the enthusiasm behind the suggestion to implement a getaddrinfo() opcode in io_uring, I must say it's not only technically nonsensical but also fundamentally at odds with the purpose and design of io_uring.

Consider taking a look at the getaddrinfo() source code: https://elixir.bootlin.com/glibc/glibc-2.39.9000/source/nss/getaddrinfo.c

It involves a series of complex operations such as socket creation, network communication, reading system files, etc., all of which are firmly within the domain of userspace.

Furthermore, the functionality of getaddrinfo() is deeply intertwined with system configuration files like /etc/hosts, /etc/resolv.conf, /etc/nsswitch.conf, etc. These files dictate the behavior of name resolution, including the order in which different sources (like DNS, hosts file, etc.) are consulted. Trying to shoehorn this functionality into the kernel-space io_uring would be impractical and disregard the established conventions of system configuration.

While it's always commendable to think outside the box, this particular request seems to miss the mark by a wide margin.

You should consider implementing io_uring in your own getaddrinfo(), not the other way around.

The relevant library for async DNS resolution is c-ares: https://github.com/c-ares/c-ares (it's not using io_uring, though).

espoal commented 3 months ago

Hey @ammarfaizi2 I agree with you on the pickiness of using getaddrinfo, and I was thinking about the same objections you just raised, BUT:

1) I'm implementing a thread per core architecture, without a traditional reactor or executor, simply having a loop and waiting for io_uring events. Performance has been AMAZING, except for the DNS and crypto parts. 2) With the raise of protocols like QUIC these will become a more and more common requirements 3) I see other big projects, like node.js, have my same issue and are migrating to liburing (pending libuv implementation). In node they spawn a thread for DNS and one for crypto

So resolving a DNS request will become a common requirements of io_uring based projects and I feel we should document somehow best approaches, even if it's not an opcode. I will spend some time to think about this and will comment on this issue, looking for further comments. Using something like c-ares might seems like a straightforward approach but it will have severe performance penalties due to the lack of an executor and reactor, very much like spawning a thread and waiting for a response in a blocking fashion.

On the other hand, wdyt of adding crypto opcodes, for example for gathering entropy?

YoSTEALTH commented 3 months ago

Talked about this many years ago https://github.com/axboe/liburing/issues/234 even though getaddrinfo has a lot of function / parser within it, the fact that DNS lookup part is in blocking state is still true.

axboe commented 3 months ago

For getaddrinfo, what @ammarfaizi2 says is spot on - this isn't really something io_uring can help you with, as it's not something that's done in the kernel to begin with.

For entropy, you can most certainly use io_uring to read eg /dev/random or /dev/urandom, for example.

espoal commented 3 months ago

Thanks @axboe , I was actually playing with /dev/random atm. How would you deal with the time syscall? It's needed for TLS and QUIC

axboe commented 3 months ago

Can you use clock_gettime()? That's generally a VDSO and hence won't even incur a syscall.

espoal commented 3 months ago

It seems like I can... thanks @axboe I really appreciate your help!

I will update this ticket with some comments on some technical corners I found, and eventually with a link to my example code.

For now this ticket can be closed.

isilence commented 3 months ago

With all that said, it'd be really great if someone implements a simple getaddrinfo() with io_uring. Perhaps, standalone at first with a separate ring, which could then evolve into a helper library to be used in frameworks and that would share a ring with them.

espoal commented 3 months ago

@isilence I'm implementing it as a state machine in Rust. I have a demo, I need to find a suitable library for parsing DNS responses, and I need to implement RustTLS on top of io_uring first.

I agree with you that even for a simple demo like mine there are a lot of consideration to take, I will make sure to document everything and ask the community for a review.

axboe commented 3 months ago

With all that said, it'd be really great if someone implements a simple getaddrinfo() with io_uring. Perhaps, standalone at first with a separate ring, which could then evolve into a helper library to be used in frameworks and that would share a ring with them.

Yeah for sure. There's no reason why liburing can't expand from basically just being an easier to use wrapper around io_uring to providing actual functionality as well.

espoal commented 3 months ago

ok so @ammarfaizi2 objection was against adding stuff like this to io_uring the kernel module, not to liburing the library used to interface with it. Good to know.