From e3c4c4175ce61280efd0f5effb233b0f2f37fab1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 2 Dec 2025 15:02:14 +1100 Subject: tcp: Always populate oaddr field for socket initiated flows When we receive a TCP connection, we get the peer address from the accept() call. In the case of a listening socket with an unspecified address (:: or 0.0.0.0) the local address of the accept()ed socket could vary. We don't get that from the accept() - we must explicitly call getsockname() to get it. Currently we avoid the latency of that extra syscall, and therefore don't populate the initiating 'oaddr' field of a flow created by an incoming TCP socket connection. This more or less works, because we rarely need that local address, but it does cause some oddities: * For migration we need the local address to recreate the socket on the destination, so we *do* call getsockname() in vhost-user mode * It limits our options in terms of forwarding connections flexibly based on the address to which they're received * It differs from UDP, where we explicitly use the IP_PKTINFO cmsg to populate oaddr. * It means (some) flow debug messages will contain wildcards instead of real local addresses In theory we can elide this call when accept()ing from a socket bound to a specific address instead of a wildcard. However to do that will need revisions to the data structures we use to keep track of listening sockets. The lack of this information is making it hard to implement some fixes we want. So, pay the price of the extra syscall to get this information, with the hope that we can later optimise it away for some cases. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- tcp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tcp.c b/tcp.c index c844da7..fa95f6b 100644 --- a/tcp.c +++ b/tcp.c @@ -2369,11 +2369,9 @@ void tcp_listen_handler(const struct ctx *c, union epoll_ref ref, ini = flow_initiate_sa(flow, ref.tcp_listen.pif, &sa, NULL, ref.tcp_listen.port); - if (c->mode == MODE_VU) { /* Rebind to same address after migration */ - if (getsockname(s, &sa.sa, &sl) || - inany_from_sockaddr(&ini->oaddr, &ini->oport, &sa) < 0) - err_perror("Can't get local address for socket %i", s); - } + if (getsockname(s, &sa.sa, &sl) || + inany_from_sockaddr(&ini->oaddr, &ini->oport, &sa) < 0) + err_perror("Can't get local address for socket %i", s); if (!inany_is_unicast(&ini->eaddr) || ini->eport == 0) { char sastr[SOCKADDR_STRLEN]; -- cgit v1.2.3