Re: UDP drops when source port is in use in the init namespace
On Tue, Sep 01, 2026 at 08:56:01PM +0200, Stefano Brivio via user wrote:
Date: Tue, 01 Sep 2026 20:56:01 +0200 (CEST) From: Stefano Brivio
To: Rahul CC: passt-user@passt.top Subject: Re: UDP drops when source port is in use in the init namespace Organization: Red Hat List-Id: "For passt users: support, questions and answers" Rahul, thanks for the report and for the investigation. Remarks and some answers inline:
On Sun, 30 Aug 2026 11:12:44 +0100 Rahul
wrote: Hi,
I'm seeing DNS requests being dropped when using pasta 20250217. As far as I can tell, UDP flows where the source port chosen in the namespace is already in use in the init namespace get dropped.
All three fwd_nat_from_*() preserve the source port for UDP:
tgt->oport = 0; if (proto == IPPROTO_UDP) /* But for UDP preserve the source port */ tgt->oport = ini->eport;
This is intended, to offer compatibility with applications or protocols that might rely on UDP source ports to be preserved, and, in general, to be as transparent as possible. But:
That forces a bind() to it, and udp_flow_sock() treats bind failure as fatal, so the flow is cancelled and the datagram dropped with no error to the sender.
...this is not, that is, it would definitely be desirable to have a fallback for bind() failures.
Probably? The danger with a fallback of this sort is that if you're using a protocol which cares about the source port it will work.. until suddenly it doesn't for pretty non-obvious reasons. Theoretically another option would be to _not_ preserve the source port by default, but allow forwarding rules to specify source-port preservation, specifically for cases which do need it. But, that's a lot more work both to implement and to configure.
I don't think I ever hit this with slirp4netns, it looks like libslirp's udp_attach() never binds a port, so the kernel just gives it a random free port.
Right, yes, slirp4netns doesn't attempt to preserve UDP source ports outside the namespace. It's a feature we added in pasta.
I'm not sure whether this is intended, but if it is, is there any way to work around it?
I see two ways of implementing this fallback mechanism, roughly:
1. pass all the way to _sock_l4() via udp_flow_sock() an additional argument to entirely ignore bind() failures (like we do for ICMP ping sockets). It might be a rather mechanical change but not my preferred approach as we would need an extra argument in a large number of functions just for a corner case
2. I think preferable: detect the failure on bind() here (it should be EADDRINUSE, did you check?) and try again from udp_flow_sock() with tgt->oport as 0.
Here, "tgt" means the target namespace of the connection, and "oport" means "our port", implying the source port (because it's an outbound connection from pasta's side).
You'll also need to make sure this takes place _before_ calling getsockname() to fill in the correct final tgt->oport.
I think it would be good to try and sketch a solution (maybe starting from 1.) to understand what approach would be more elegant and viable.
I don't have much time on my hands right now but I'll definitely provide pointers and support if you feel like proposing a patch for this.
As a first test / workaround for your usage: did you already check that keeping tgt->oport as 0 in the relevant function in fwd.c works?
-- Stefano
_______________________________________________ user mailing list -- passt-user@passt.top To unsubscribe send an email to passt-user-leave@passt.top
-- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson
participants (1)
-
David Gibson