* [PATCH liburing v3 1/4] liburing: Introduce getsockname operation
2025-12-03 19:52 [PATCH liburing v3 0/4] liburing: getsockname support Gabriel Krisman Bertazi
@ 2025-12-03 19:52 ` Gabriel Krisman Bertazi
2025-12-03 19:52 ` [PATCH liburing v3 2/4] test/bind-listen.t: Use ephemeral port Gabriel Krisman Bertazi
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-12-03 19:52 UTC (permalink / raw)
To: Jens Axboe; +Cc: Gabriel Krisman Bertazi, io-uring, csander
This implements the functionality of getsockname(2) and getpeername(2)
under a single operation.
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
src/include/liburing.h | 13 +++++++++++++
src/include/liburing/io_uring.h | 1 +
2 files changed, 14 insertions(+)
diff --git a/src/include/liburing.h b/src/include/liburing.h
index 83819eb7..1626f3bb 100644
--- a/src/include/liburing.h
+++ b/src/include/liburing.h
@@ -1572,6 +1572,19 @@ IOURINGINLINE void io_uring_prep_cmd_sock(struct io_uring_sqe *sqe,
sqe->level = level;
}
+IOURINGINLINE void io_uring_prep_cmd_getsockname(struct io_uring_sqe *sqe,
+ int fd, struct sockaddr *sockaddr,
+ socklen_t *sockaddr_len,
+ int peer)
+ LIBURING_NOEXCEPT
+{
+ io_uring_prep_uring_cmd(sqe, SOCKET_URING_OP_GETSOCKNAME, fd);
+
+ sqe->addr = (uintptr_t) sockaddr;
+ sqe->addr3 = (unsigned long) (uintptr_t) sockaddr_len;
+ sqe->optlen = peer;
+}
+
IOURINGINLINE void io_uring_prep_waitid(struct io_uring_sqe *sqe,
idtype_t idtype,
id_t id,
diff --git a/src/include/liburing/io_uring.h b/src/include/liburing/io_uring.h
index a54e5b42..8e8b8e6a 100644
--- a/src/include/liburing/io_uring.h
+++ b/src/include/liburing/io_uring.h
@@ -966,6 +966,7 @@ enum io_uring_socket_op {
SOCKET_URING_OP_GETSOCKOPT,
SOCKET_URING_OP_SETSOCKOPT,
SOCKET_URING_OP_TX_TIMESTAMP,
+ SOCKET_URING_OP_GETSOCKNAME,
};
/*
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH liburing v3 2/4] test/bind-listen.t: Use ephemeral port
2025-12-03 19:52 [PATCH liburing v3 0/4] liburing: getsockname support Gabriel Krisman Bertazi
2025-12-03 19:52 ` [PATCH liburing v3 1/4] liburing: Introduce getsockname operation Gabriel Krisman Bertazi
@ 2025-12-03 19:52 ` Gabriel Krisman Bertazi
2025-12-03 19:52 ` [PATCH liburing v3 3/4] bind-listen.t: Add tests for getsockname Gabriel Krisman Bertazi
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-12-03 19:52 UTC (permalink / raw)
To: Jens Axboe; +Cc: Gabriel Krisman Bertazi, io-uring, csander
This test fails if port 8000 is already in use by something else. Now
that we have getsockname with direct file descriptors, use an ephemeral
port instead. To avoid regressing old systems, bite the bullet and do
the syscall version for older kernels, fixing the test there as well.
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
since v2:
- don't fail on older kernels
---
test/bind-listen.c | 89 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 79 insertions(+), 10 deletions(-)
diff --git a/test/bind-listen.c b/test/bind-listen.c
index 6f80f177..a468aa94 100644
--- a/test/bind-listen.c
+++ b/test/bind-listen.c
@@ -22,7 +22,7 @@ static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
}
static const char *magic = "Hello World!";
-static int use_port = 8000;
+static bool no_getsockname = false;
enum {
SRV_INDEX = 0,
@@ -74,18 +74,82 @@ static int connect_client(struct io_uring *ring, unsigned short peer_port)
return T_SETUP_OK;
}
-static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
+/*
+ * getsockname was added to the kernel a few releases after bind/listen.
+ * In order to provide a backward-compatible test, fallback to
+ * non-io-uring if we are on an older kernel, allowing the test to
+ * continue.
+ */
+static int do_getsockname(struct io_uring *ring, int direct_socket,
+ int peer, struct sockaddr *saddr,
+ socklen_t *saddr_len)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int res, fd;
+
+ if (!no_getsockname) {
+ /* attempt io_uring. Commmand might not exist */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cmd_getsockname(sqe, direct_socket,
+ saddr, saddr_len, peer);
+ sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
+ io_uring_submit(ring);
+ io_uring_wait_cqe(ring, &cqe);
+ res = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (no_getsockname || res == -ENOTSUP) {
+ /*
+ * Older kernel. install the fd and use the getsockname
+ * syscall.
+ */
+ no_getsockname = true;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, direct_socket, 0);
+ io_uring_submit(ring);
+ io_uring_wait_cqe(ring, &cqe);
+ fd = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+
+ if (fd < 0) {
+ fprintf(stderr, "installing direct fd failed. %d\n",
+ cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (peer)
+ res = getpeername(fd, saddr, saddr_len);
+ else
+ res = getsockname(fd, saddr, saddr_len);
+
+ if (res) {
+ fprintf(stderr, "get%sname syscall failed. %d\n",
+ peer? "peer":"sock", errno);
+ return T_EXIT_FAIL;
+ }
+ close(fd);
+ } else if (res < 0) {
+ fprintf(stderr, "getsockname server failed. %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ return 0;
+}
+
+static int setup_srv(struct io_uring *ring)
{
+ struct sockaddr_in server_addr;
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
struct __kernel_timespec ts;
int ret, val, submitted;
unsigned head;
- memset(server_addr, 0, sizeof(struct sockaddr_in));
- server_addr->sin_family = AF_INET;
- server_addr->sin_port = htons(use_port++);
- server_addr->sin_addr.s_addr = htons(INADDR_ANY);
+ memset(&server_addr, 0, sizeof(struct sockaddr_in));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(0);
+ server_addr.sin_addr.s_addr = htons(INADDR_ANY);
sqe = io_uring_get_sqe(ring);
io_uring_prep_socket_direct(sqe, AF_INET, SOCK_STREAM, 0, SRV_INDEX, 0);
@@ -98,7 +162,7 @@ static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
sqe = io_uring_get_sqe(ring);
- io_uring_prep_bind(sqe, SRV_INDEX, (struct sockaddr *) server_addr,
+ io_uring_prep_bind(sqe, SRV_INDEX, (struct sockaddr *) &server_addr,
sizeof(struct sockaddr_in));
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
@@ -132,7 +196,8 @@ static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
static int test_good_server(unsigned int ring_flags)
{
- struct sockaddr_in server_addr;
+ struct sockaddr_in saddr = {};
+ socklen_t saddr_len = sizeof(saddr);
struct __kernel_timespec ts;
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
@@ -155,13 +220,17 @@ static int test_good_server(unsigned int ring_flags)
return T_SETUP_SKIP;
}
- ret = setup_srv(&ring, &server_addr);
+ ret = setup_srv(&ring);
if (ret != T_SETUP_OK) {
fprintf(stderr, "srv startup failed.\n");
return T_EXIT_FAIL;
}
- if (connect_client(&ring, server_addr.sin_port) != T_SETUP_OK) {
+ if (do_getsockname(&ring, SRV_INDEX, 0, (struct sockaddr*) &saddr,
+ &saddr_len))
+ return T_EXIT_FAIL;
+
+ if (connect_client(&ring, saddr.sin_port) != T_SETUP_OK) {
fprintf(stderr, "cli startup failed.\n");
return T_SETUP_SKIP;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH liburing v3 3/4] bind-listen.t: Add tests for getsockname
2025-12-03 19:52 [PATCH liburing v3 0/4] liburing: getsockname support Gabriel Krisman Bertazi
2025-12-03 19:52 ` [PATCH liburing v3 1/4] liburing: Introduce getsockname operation Gabriel Krisman Bertazi
2025-12-03 19:52 ` [PATCH liburing v3 2/4] test/bind-listen.t: Use ephemeral port Gabriel Krisman Bertazi
@ 2025-12-03 19:52 ` Gabriel Krisman Bertazi
2025-12-03 19:52 ` [PATCH liburing v3 4/4] man/io_uring_prep_getsockname.3: Add man page Gabriel Krisman Bertazi
2025-12-03 20:23 ` [PATCH liburing v3 0/4] liburing: getsockname support Jens Axboe
4 siblings, 0 replies; 6+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-12-03 19:52 UTC (permalink / raw)
To: Jens Axboe; +Cc: Gabriel Krisman Bertazi, io-uring, csander
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
test/bind-listen.c | 99 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 96 insertions(+), 3 deletions(-)
diff --git a/test/bind-listen.c b/test/bind-listen.c
index a468aa94..38200879 100644
--- a/test/bind-listen.c
+++ b/test/bind-listen.c
@@ -202,7 +202,7 @@ static int test_good_server(unsigned int ring_flags)
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
struct io_uring ring;
- int ret;
+ int ret, port;
int fds[3];
char buf[1024];
@@ -235,7 +235,7 @@ static int test_good_server(unsigned int ring_flags)
return T_SETUP_SKIP;
}
- /* Wait for a request */
+ /* Wait for a connection */
sqe = io_uring_get_sqe(&ring);
io_uring_prep_accept_direct(sqe, SRV_INDEX, NULL, NULL, 0, CONN_INDEX);
sqe->flags |= IOSQE_FIXED_FILE;
@@ -248,6 +248,22 @@ static int test_good_server(unsigned int ring_flags)
}
io_uring_cqe_seen(&ring, cqe);
+ /* Test that getsockname on the peer (getpeername) yields a
+ * sane result.
+ */
+ port = saddr.sin_port;
+ saddr.sin_port = 0;
+ if (do_getsockname(&ring, CLI_INDEX, 1,
+ (struct sockaddr*)&saddr, &saddr_len))
+ return T_EXIT_FAIL;
+
+ if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) ||
+ saddr.sin_port != port) {
+ fprintf(stderr, "getsockname peer got wrong address: %s:%d\n",
+ inet_ntoa(saddr.sin_addr), saddr.sin_port);
+ return T_EXIT_FAIL;
+ }
+
sqe = io_uring_get_sqe(&ring);
io_uring_prep_recv(sqe, CONN_INDEX, buf, sizeof(buf), 0);
sqe->flags |= IOSQE_FIXED_FILE;
@@ -424,6 +440,77 @@ fail:
return ret;
}
+static int test_bad_sockname(void)
+{
+ struct sockaddr_in saddr;
+ socklen_t saddr_len;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ int sock = -1, err;
+ int ret = T_EXIT_FAIL;
+
+ memset(&saddr, 0, sizeof(struct sockaddr_in));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(8001);
+ saddr.sin_addr.s_addr = htons(INADDR_ANY);
+
+ err = t_create_ring(1, &ring, 0);
+ if (err < 0) {
+ fprintf(stderr, "queue_init: %d\n", err);
+ return T_SETUP_SKIP;
+ }
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("socket");
+ goto fail;
+ }
+
+ err = t_bind_ephemeral_port(sock, &saddr);
+ if (err) {
+ fprintf(stderr, "bind: %s\n", strerror(-err));
+ goto fail;
+ }
+
+ /* getsockname on a !socket fd. with getsockname(2), this would
+ * return -ENOTSOCK, but we can't do it in an io_uring_cmd.
+ */
+ sqe = io_uring_get_sqe(&ring);
+ saddr_len = sizeof(saddr);
+ io_uring_prep_cmd_getsockname(sqe, 1, (struct sockaddr*)&saddr, &saddr_len, 0);
+ err = io_uring_submit(&ring);
+ if (err < 0)
+ goto fail;
+ err = io_uring_wait_cqe(&ring, &cqe);
+ if (err)
+ goto fail;
+ if (cqe->res != -ENOTSUP)
+ goto fail;
+ io_uring_cqe_seen(&ring, cqe);
+
+ /* getsockname with weird parameters */
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_cmd_getsockname(sqe, sock, (struct sockaddr*)&saddr,
+ &saddr_len, 3);
+ err = io_uring_submit(&ring);
+ if (err < 0)
+ goto fail;
+ err = io_uring_wait_cqe(&ring, &cqe);
+ if (err)
+ goto fail;
+ if (cqe->res != -EINVAL)
+ goto fail;
+ io_uring_cqe_seen(&ring, cqe);
+
+ ret = T_EXIT_PASS;
+fail:
+ io_uring_queue_exit(&ring);
+ if (sock != -1)
+ close(sock);
+ return ret;
+}
+
int main(int argc, char *argv[])
{
struct io_uring_probe *probe;
@@ -472,6 +559,12 @@ int main(int argc, char *argv[])
fprintf(stderr, "bad listen failed\n");
return T_EXIT_FAIL;
}
-
+ if (!no_getsockname) {
+ ret = test_bad_sockname();
+ if (ret) {
+ fprintf(stderr, "bad sockname failed\n");
+ return T_EXIT_FAIL;
+ }
+ }
return T_EXIT_PASS;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH liburing v3 4/4] man/io_uring_prep_getsockname.3: Add man page
2025-12-03 19:52 [PATCH liburing v3 0/4] liburing: getsockname support Gabriel Krisman Bertazi
` (2 preceding siblings ...)
2025-12-03 19:52 ` [PATCH liburing v3 3/4] bind-listen.t: Add tests for getsockname Gabriel Krisman Bertazi
@ 2025-12-03 19:52 ` Gabriel Krisman Bertazi
2025-12-03 20:23 ` [PATCH liburing v3 0/4] liburing: getsockname support Jens Axboe
4 siblings, 0 replies; 6+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-12-03 19:52 UTC (permalink / raw)
To: Jens Axboe; +Cc: Gabriel Krisman Bertazi, io-uring, csander
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
since v2:
- Fix Jens comments
---
man/io_uring_prep_getsockname.3 | 78 +++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
create mode 100644 man/io_uring_prep_getsockname.3
diff --git a/man/io_uring_prep_getsockname.3 b/man/io_uring_prep_getsockname.3
new file mode 100644
index 00000000..de78cb40
--- /dev/null
+++ b/man/io_uring_prep_getsockname.3
@@ -0,0 +1,78 @@
+.\" Copyright (C) 2024 SUSE LLC.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+.TH io_uring_prep_getsockname 3 "Dec 3, 2025" "liburing-2.13" "liburing Manual"
+.SH NAME
+io_uring_prep_getsockname \- prepare a getsockname or getpeername request
+.SH SYNOPSIS
+.nf
+.B #include <sys/socket.h>
+.B #include <liburing.h>
+.PP
+.BI "void io_uring_prep_getsockname(struct io_uring_sqe *" sqe ","
+.BI " int " sockfd ","
+.BI " struct sockaddr *" sockaddr ","
+.BI " socklen_t *" sockaddr_len ","
+.BI " int " peer ");"
+.fi
+.SH DESCRIPTION
+The
+.BR io_uring_prep_getsockname (3)
+function prepares a getsockname/getpeername request.
+The submission queue entry
+.I sqe
+is setup to fetch the locally bound address or peer address of the socket
+file descriptor pointed by
+.IR sockfd .
+The parameter
+.IR sockaddr
+points to a region of size
+.IR sockaddr_len
+where the output is written.
+.IR sockaddr_len
+is modified by the kernel to indicate how many bytes were written.
+The output address is the locally bound address if
+.IR peer
+is set to
+.B 0
+or the peer address if
+.IR peer
+is set to
+.BR 1 .
+
+This function prepares an async
+.BR getsockname (2)
+or
+.BR getpeername (2)
+request. See those man pages for details.
+
+.SH RETURN VALUE
+None
+.SH ERRORS
+The CQE
+.I res
+field will contain the result of the operation. See the related man page for
+details on possible values. Note that where synchronous system calls will return
+.B -1
+on failure and set
+.I errno
+to the actual error value, io_uring never uses
+.IR errno .
+Instead it returns the negated
+.I errno
+directly in the CQE
+.I res
+field.
+.BR
+Differently from the equivalent system calls, if the user attempts to
+use this operation on a non-socket file descriptor, the CQE error result
+is
+.IR -ENOTSUP
+instead of
+.IR ENOSOCK.
+.SH SEE ALSO
+.BR io_uring_get_sqe (3),
+.BR io_uring_submit (3),
+.BR io_uring_prep_getsockname (2)
+.BR io_uring_prep_getpeername (2)
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH liburing v3 0/4] liburing: getsockname support
2025-12-03 19:52 [PATCH liburing v3 0/4] liburing: getsockname support Gabriel Krisman Bertazi
` (3 preceding siblings ...)
2025-12-03 19:52 ` [PATCH liburing v3 4/4] man/io_uring_prep_getsockname.3: Add man page Gabriel Krisman Bertazi
@ 2025-12-03 20:23 ` Jens Axboe
4 siblings, 0 replies; 6+ messages in thread
From: Jens Axboe @ 2025-12-03 20:23 UTC (permalink / raw)
To: Gabriel Krisman Bertazi; +Cc: io-uring, csander
On Wed, 03 Dec 2025 14:52:14 -0500, Gabriel Krisman Bertazi wrote:
> Changes since v2:
>
> The main change from the previous iteration is ensuring the test won't
> regress in older kernels. This is done by installing the socket fd and
> fallbacking to the syscall. I avoided reverting to using a fixed port
> because that is flaky and would also require recreating the socket.
>
> [...]
Applied, thanks!
[1/4] liburing: Introduce getsockname operation
commit: c1541b0421602ea26ce1c5bba9f3a9403224f971
[2/4] test/bind-listen.t: Use ephemeral port
commit: 79ef754d7bff5c8216b57b4eed42448f28a4e88a
[3/4] bind-listen.t: Add tests for getsockname
commit: a75b1b69e437311c7b3c9839a7d4510fb9be20a3
[4/4] man/io_uring_prep_getsockname.3: Add man page
commit: 419c9ca5bf5d6dd942504213a68a4862e733392b
Best regards,
--
Jens Axboe
^ permalink raw reply [flat|nested] 6+ messages in thread