* [PATCH 0/3] Allow listen functions to return fds
@ 2026-01-05 8:28 David Gibson
2026-01-05 8:28 ` [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing David Gibson
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: David Gibson @ 2026-01-05 8:28 UTC (permalink / raw)
To: Stefano Brivio, passt-dev; +Cc: David Gibson
For future forwarding changes, it makes more sense for the tcp and udp
listen functions to return socket fds, rather than just success /
failure. Make the change, fixing bug 186 and adding a debugging
option along the way.
Link: https://bugs.passt.top/show_bug.cgi?id=186
David Gibson (3):
conf: Introduce --no-bindtodevice option for testing
tcp, udp, conf: Don't silently ignore listens on unsupported IP
versions
tcp, udp: Make {tcp,udp}_listen() return socket fds
conf.c | 26 +++++++++++++++++++-------
passt.1 | 6 ++++++
tcp.c | 13 ++++---------
udp.c | 10 ++++------
4 files changed, 33 insertions(+), 22 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing
2026-01-05 8:28 [PATCH 0/3] Allow listen functions to return fds David Gibson
@ 2026-01-05 8:28 ` David Gibson
2026-01-10 23:33 ` Stefano Brivio
2026-01-05 8:28 ` [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions David Gibson
2026-01-05 8:28 ` [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds David Gibson
2 siblings, 1 reply; 15+ messages in thread
From: David Gibson @ 2026-01-05 8:28 UTC (permalink / raw)
To: Stefano Brivio, passt-dev; +Cc: David Gibson
We need to support (as best we can) older kernels which don't allow
unprivilieged processes to use the SO_BINDTODEVICE socket option.
Fallcaks for that case are controlled by the c->no_bindtodevice variable.
Currently testing behaviour of those fallbacks requires setting up a test
system with a kernel that doesn't support the option, which is pretty
awkward. We can test it almost as well and much more easily by adding a
command line option to explicitly disable use of SO_BINDTODEVICE.
Like --no-splice this is envisaged as something for developers' and
testers' convenience, not a supported option for end users. The man page
text reflects that.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
conf.c | 2 ++
passt.1 | 6 ++++++
2 files changed, 8 insertions(+)
diff --git a/conf.c b/conf.c
index ceb9aa55..70ea168c 100644
--- a/conf.c
+++ b/conf.c
@@ -962,6 +962,7 @@ static void usage(const char *name, FILE *f, int status)
" --no-ndp Disable NDP responses\n"
" --no-dhcpv6 Disable DHCPv6 server\n"
" --no-ra Disable router advertisements\n"
+ " --no-bindtodevice Disable SO_BINDTODEVICE\n"
" --freebind Bind to any address for forwarding\n"
" --no-map-gw Don't map gateway address to host\n"
" -4, --ipv4-only Enable IPv4 operation only\n"
@@ -1454,6 +1455,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 },
{"no-ndp", no_argument, &c->no_ndp, 1 },
{"no-ra", no_argument, &c->no_ra, 1 },
+ {"no-bindtodevice", no_argument, &c->no_bindtodevice, 1},
{"no-splice", no_argument, &c->no_splice, 1 },
{"freebind", no_argument, &c->freebind, 1 },
{"no-map-gw", no_argument, &no_map_gw, 1 },
diff --git a/passt.1 b/passt.1
index db0d6620..4859d9e5 100644
--- a/passt.1
+++ b/passt.1
@@ -348,6 +348,12 @@ namespace will be silently dropped.
Disable Router Advertisements. Router Solicitations coming from guest or target
namespace will be ignored.
+.TP
+.BR \-\-no-bindtodevice
+Development/testing option, do not use. Disables use of
+SO_BINDTODEVICE socket option. Implicitly enabled on older kernels
+which don't permit unprivileged use of SO_BINDTODEVICE.
+
.TP
.BR \-\-freebind
Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
--
2.52.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions
2026-01-05 8:28 [PATCH 0/3] Allow listen functions to return fds David Gibson
2026-01-05 8:28 ` [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing David Gibson
@ 2026-01-05 8:28 ` David Gibson
2026-01-10 23:33 ` Stefano Brivio
2026-01-05 8:28 ` [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds David Gibson
2 siblings, 1 reply; 15+ messages in thread
From: David Gibson @ 2026-01-05 8:28 UTC (permalink / raw)
To: Stefano Brivio, passt-dev; +Cc: David Gibson
Currently, it's possible to explicitly ask for forwarding from an IPv4
address, while disabling IPv4:
$ pasta -t 192.0.2.1/12345 -6
or vice versa:
$ pasta -t 2001:db8::1/12345 -4
Currently, the impossible to implement forwarding option will be silently
ignored. That's potentially confusing since in a complex setup, it might
not be obvious why the requested forward isn't taking effect.
Specifically, it's ignored at a fairly low level: tcp_listen() and
udp_listen() ignore it and return 0. Those run kind of late to give a
good error message. Change the low-level functions to return -EACCES
(chosen because that's what the kernel will return if you request IPv6
when it's disabled by sysctl). Most callers of {tcp,udp}_listen() ignore
the return code, so this is a no-op for them. In the remaining caller,
conf_ports_range_except() check for the case explicitly, and provide a
meaningful error message.
Of itself, this bug is insignificant, but this is a roadblock to having
{tcp,udp}_listen() return socket fds, which in turn is a roadblock to my
flexible forwarding work. So, might as well fix it.
Link: https://bugs.passt.top/show_bug.cgi?id=186
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
conf.c | 10 ++++++++++
tcp.c | 6 ++----
udp.c | 6 ++----
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/conf.c b/conf.c
index 70ea168c..cc3c20a9 100644
--- a/conf.c
+++ b/conf.c
@@ -162,6 +162,16 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
optname, optarg);
}
+ if (addr) {
+ if (!c->ifi4 && inany_v4(addr)) {
+ die("IPv4 is disabled, can't use -%c %s",
+ optname, optarg);
+ } else if (!c->ifi6 && !inany_v4(addr)) {
+ die("IPv6 is disabled, can't use -%c %s",
+ optname, optarg);
+ }
+ }
+
for (i = first; i <= last; i++) {
if (bitmap_isset(exclude, i))
continue;
diff --git a/tcp.c b/tcp.c
index e7fa85f3..67007c05 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2700,16 +2700,14 @@ int tcp_listen(const struct ctx *c, uint8_t pif,
/* Restrict to v6 only */
addr = &inany_any6;
else if (inany_v4(addr))
- /* Nothing to do */
- return 0;
+ return -EACCES;
}
if (!c->ifi6) {
if (!addr)
/* Restrict to v4 only */
addr = &inany_any4;
else if (!inany_v4(addr))
- /* Nothing to do */
- return 0;
+ return -EACCES;
}
if (pif == PIF_HOST) {
diff --git a/udp.c b/udp.c
index eda55c39..8cfa1e1f 100644
--- a/udp.c
+++ b/udp.c
@@ -1162,16 +1162,14 @@ int udp_listen(const struct ctx *c, uint8_t pif,
/* Restrict to v6 only */
addr = &inany_any6;
else if (inany_v4(addr))
- /* Nothing to do */
- return 0;
+ return -EACCES;
}
if (!c->ifi6) {
if (!addr)
/* Restrict to v4 only */
addr = &inany_any4;
else if (!inany_v4(addr))
- /* Nothing to do */
- return 0;
+ return -EACCES;
}
s = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, pif,
--
2.52.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds
2026-01-05 8:28 [PATCH 0/3] Allow listen functions to return fds David Gibson
2026-01-05 8:28 ` [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing David Gibson
2026-01-05 8:28 ` [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions David Gibson
@ 2026-01-05 8:28 ` David Gibson
2026-01-10 23:33 ` Stefano Brivio
2 siblings, 1 reply; 15+ messages in thread
From: David Gibson @ 2026-01-05 8:28 UTC (permalink / raw)
To: Stefano Brivio, passt-dev; +Cc: David Gibson
{tcp,udp}_listen() currently return 0 on success, rather than the socket
fd they created. Historically, that was because these functions could
sometimes create multiple sockets. We've now refactored things to avoid
that, so it makes more sense for them to return the socket on success.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
conf.c | 14 +++++++-------
tcp.c | 7 ++-----
udp.c | 4 ++--
3 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/conf.c b/conf.c
index cc3c20a9..5db49653 100644
--- a/conf.c
+++ b/conf.c
@@ -149,7 +149,7 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
{
bool bound_one = false;
unsigned i;
- int ret;
+ int fd;
if (first == 0) {
die("Can't forward port 0 for option '-%c %s'",
@@ -185,23 +185,23 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
fwd->delta[i] = to - first;
if (optname == 't')
- ret = tcp_listen(c, PIF_HOST, addr, ifname, i);
+ fd = tcp_listen(c, PIF_HOST, addr, ifname, i);
else if (optname == 'u')
- ret = udp_listen(c, PIF_HOST, addr, ifname, i);
+ fd = udp_listen(c, PIF_HOST, addr, ifname, i);
else
/* No way to check in advance for -T and -U */
- ret = 0;
+ fd = 0;
- if (ret == -ENFILE || ret == -EMFILE) {
+ if (fd == -ENFILE || fd == -EMFILE) {
die("Can't open enough sockets for port specifier: %s",
optarg);
}
- if (!ret) {
+ if (fd >= 0) {
bound_one = true;
} else if (!weak) {
die("Failed to bind port %u (%s) for option '-%c %s'",
- i, strerror_(-ret), optname, optarg);
+ i, strerror_(-fd), optname, optarg);
}
}
diff --git a/tcp.c b/tcp.c
index 67007c05..80b47f3c 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2680,7 +2680,7 @@ void tcp_sock_handler(const struct ctx *c, union epoll_ref ref,
* @ifname: Name of interface to bind to, NULL for any
* @port: Port, host order
*
- * Return: 0 on success, negative error code on failure
+ * Return: Socket fd on success, negative error code on failure
*/
int tcp_listen(const struct ctx *c, uint8_t pif,
const union inany_addr *addr, const char *ifname, in_port_t port)
@@ -2729,10 +2729,7 @@ int tcp_listen(const struct ctx *c, uint8_t pif,
socks[port][V6] = s < 0 ? -1 : s;
}
- if (s < 0)
- return s;
-
- return 0;
+ return s;
}
/**
diff --git a/udp.c b/udp.c
index 8cfa1e1f..63dc7c25 100644
--- a/udp.c
+++ b/udp.c
@@ -1136,7 +1136,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
* @ifname: Name of interface to bind to, NULL if not configured
* @port: Port, host order
*
- * Return: 0 on success, negative error code on failure
+ * Return: Socket fd on success, negative error code on failure
*/
int udp_listen(const struct ctx *c, uint8_t pif,
const union inany_addr *addr, const char *ifname, in_port_t port)
@@ -1180,7 +1180,7 @@ int udp_listen(const struct ctx *c, uint8_t pif,
if (!addr || !inany_v4(addr))
socks[V6][port] = s < 0 ? -1 : s;
- return s < 0 ? s : 0;
+ return s;
}
/**
--
2.52.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing
2026-01-05 8:28 ` [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing David Gibson
@ 2026-01-10 23:33 ` Stefano Brivio
2026-01-12 3:42 ` David Gibson
0 siblings, 1 reply; 15+ messages in thread
From: Stefano Brivio @ 2026-01-10 23:33 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On Mon, 5 Jan 2026 19:28:48 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> We need to support (as best we can) older kernels which don't allow
> unprivilieged processes to use the SO_BINDTODEVICE socket option.
Nit: unprivileged
> Fallcaks for that case are controlled by the c->no_bindtodevice variable.
Fallbacks
> Currently testing behaviour of those fallbacks requires setting up a test
> system with a kernel that doesn't support the option, which is pretty
> awkward. We can test it almost as well and much more easily by adding a
> command line option to explicitly disable use of SO_BINDTODEVICE.
It's kind of hard to understand if this patch entirely does that, I
think.
We still have a separate, implicit probing of SO_BINDTODEVICE in
sock_l4_(), which is perhaps excluded by c->no_bindtodevice (but then
the comment is misleading?).
> Like --no-splice this is envisaged as something for developers' and
> testers' convenience, not a supported option for end users. The man page
> text reflects that.
I never really understood the point of --no-splice, as there was no
user request whatsoever behind it, but fine, the argument was that it
added some needed functionality, even though I couldn't quite grasp
which one it was.
However, with this, the question is where we draw the line. There are
probably other options we could use to make debugging or testing
slightly simpler, but if they don't offer actual functionality, we
always kept them out so far.
That's because we already have a long list of options and making it
unnecessarily longer is a disservice to users, I think.
Would using something like this:
sed -i 's/(\(setsockopt([a-z]*, SOL_SOCKET, SO_BINDTODEVICE\)/((errno = EPERM) || \1/g' *.c
be totally outrageous, for testing purposes?
It has the advantage of making it easier to verify if we're really
disabling the usage of SO_BINDTODEVICE on all the paths (together with
grep / git / editors), and not introducing additional command line
options.
Another trick I use sometimes to selectively disable or enable kernel
features is to handle system calls via seitan, in this case the
(simple) recipe would something like:
[
{
"match": [
{ "setsockopt": { "level": socket", "name": "bindtodevice" } }
],
"return": { "value": "EPERM", "error": -1 }
}
]
but I haven't implemented setsockopt() yet. :(
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> conf.c | 2 ++
> passt.1 | 6 ++++++
> 2 files changed, 8 insertions(+)
>
> diff --git a/conf.c b/conf.c
> index ceb9aa55..70ea168c 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -962,6 +962,7 @@ static void usage(const char *name, FILE *f, int status)
> " --no-ndp Disable NDP responses\n"
> " --no-dhcpv6 Disable DHCPv6 server\n"
> " --no-ra Disable router advertisements\n"
> + " --no-bindtodevice Disable SO_BINDTODEVICE\n"
> " --freebind Bind to any address for forwarding\n"
> " --no-map-gw Don't map gateway address to host\n"
> " -4, --ipv4-only Enable IPv4 operation only\n"
> @@ -1454,6 +1455,7 @@ void conf(struct ctx *c, int argc, char **argv)
> {"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 },
> {"no-ndp", no_argument, &c->no_ndp, 1 },
> {"no-ra", no_argument, &c->no_ra, 1 },
> + {"no-bindtodevice", no_argument, &c->no_bindtodevice, 1},
> {"no-splice", no_argument, &c->no_splice, 1 },
> {"freebind", no_argument, &c->freebind, 1 },
> {"no-map-gw", no_argument, &no_map_gw, 1 },
> diff --git a/passt.1 b/passt.1
> index db0d6620..4859d9e5 100644
> --- a/passt.1
> +++ b/passt.1
> @@ -348,6 +348,12 @@ namespace will be silently dropped.
> Disable Router Advertisements. Router Solicitations coming from guest or target
> namespace will be ignored.
>
> +.TP
> +.BR \-\-no-bindtodevice
> +Development/testing option, do not use. Disables use of
> +SO_BINDTODEVICE socket option. Implicitly enabled on older kernels
> +which don't permit unprivileged use of SO_BINDTODEVICE.
> +
> .TP
> .BR \-\-freebind
> Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
The change looks otherwise good to me... I just hope we can avoid it
somehow, but if not, so be it.
--
Stefano
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions
2026-01-05 8:28 ` [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions David Gibson
@ 2026-01-10 23:33 ` Stefano Brivio
2026-01-12 3:48 ` David Gibson
0 siblings, 1 reply; 15+ messages in thread
From: Stefano Brivio @ 2026-01-10 23:33 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On Mon, 5 Jan 2026 19:28:49 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> Currently, it's possible to explicitly ask for forwarding from an IPv4
> address, while disabling IPv4:
> $ pasta -t 192.0.2.1/12345 -6
> or vice versa:
> $ pasta -t 2001:db8::1/12345 -4
>
> Currently, the impossible to implement forwarding option will be silently
> ignored. That's potentially confusing since in a complex setup, it might
> not be obvious why the requested forward isn't taking effect.
>
> Specifically, it's ignored at a fairly low level: tcp_listen() and
> udp_listen() ignore it and return 0. Those run kind of late to give a
> good error message. Change the low-level functions to return -EACCES
> (chosen because that's what the kernel will return if you request IPv6
> when it's disabled by sysctl).
I couldn't quite find out in which case EACCES is returned by the
kernel. If I set /proc/sys/net/ipv6/conf/all/disable_ipv6 to 1 and then
bind() an IPv6 address, after setting IPV6_FREEBIND, I get 0.
If I disable IPv6 via command line (ipv6.disable=1) I get EAFNOSUPPORT
on bind(), and EOPNOTSUPP on setting addresses and routes. EACCES, I
couldn't quite spot it yet.
> Most callers of {tcp,udp}_listen() ignore
> the return code, so this is a no-op for them. In the remaining caller,
> conf_ports_range_except() check for the case explicitly, and provide a
> meaningful error message.
>
> Of itself, this bug is insignificant, but this is a roadblock to having
> {tcp,udp}_listen() return socket fds, which in turn is a roadblock to my
> flexible forwarding work. So, might as well fix it.
>
> Link: https://bugs.passt.top/show_bug.cgi?id=186
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> conf.c | 10 ++++++++++
> tcp.c | 6 ++----
> udp.c | 6 ++----
> 3 files changed, 14 insertions(+), 8 deletions(-)
>
> diff --git a/conf.c b/conf.c
> index 70ea168c..cc3c20a9 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -162,6 +162,16 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
> optname, optarg);
> }
>
> + if (addr) {
> + if (!c->ifi4 && inany_v4(addr)) {
> + die("IPv4 is disabled, can't use -%c %s",
> + optname, optarg);
> + } else if (!c->ifi6 && !inany_v4(addr)) {
> + die("IPv6 is disabled, can't use -%c %s",
> + optname, optarg);
> + }
> + }
> +
> for (i = first; i <= last; i++) {
> if (bitmap_isset(exclude, i))
> continue;
> diff --git a/tcp.c b/tcp.c
> index e7fa85f3..67007c05 100644
> --- a/tcp.c
> +++ b/tcp.c
> @@ -2700,16 +2700,14 @@ int tcp_listen(const struct ctx *c, uint8_t pif,
> /* Restrict to v6 only */
> addr = &inany_any6;
> else if (inany_v4(addr))
> - /* Nothing to do */
> - return 0;
> + return -EACCES;
> }
> if (!c->ifi6) {
> if (!addr)
> /* Restrict to v4 only */
> addr = &inany_any4;
> else if (!inany_v4(addr))
> - /* Nothing to do */
> - return 0;
> + return -EACCES;
> }
>
> if (pif == PIF_HOST) {
> diff --git a/udp.c b/udp.c
> index eda55c39..8cfa1e1f 100644
> --- a/udp.c
> +++ b/udp.c
> @@ -1162,16 +1162,14 @@ int udp_listen(const struct ctx *c, uint8_t pif,
> /* Restrict to v6 only */
> addr = &inany_any6;
> else if (inany_v4(addr))
> - /* Nothing to do */
> - return 0;
> + return -EACCES;
> }
> if (!c->ifi6) {
> if (!addr)
> /* Restrict to v4 only */
> addr = &inany_any4;
> else if (!inany_v4(addr))
> - /* Nothing to do */
> - return 0;
> + return -EACCES;
> }
>
> s = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, pif,
The rest looks good to me.
--
Stefano
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds
2026-01-05 8:28 ` [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds David Gibson
@ 2026-01-10 23:33 ` Stefano Brivio
2026-01-12 3:50 ` David Gibson
0 siblings, 1 reply; 15+ messages in thread
From: Stefano Brivio @ 2026-01-10 23:33 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On Mon, 5 Jan 2026 19:28:50 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> {tcp,udp}_listen() currently return 0 on success, rather than the socket
> fd they created. Historically, that was because these functions could
> sometimes create multiple sockets. We've now refactored things to avoid
> that, so it makes more sense for them to return the socket on success.
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> conf.c | 14 +++++++-------
> tcp.c | 7 ++-----
> udp.c | 4 ++--
> 3 files changed, 11 insertions(+), 14 deletions(-)
>
> diff --git a/conf.c b/conf.c
> index cc3c20a9..5db49653 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -149,7 +149,7 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
> {
> bool bound_one = false;
> unsigned i;
> - int ret;
> + int fd;
>
> if (first == 0) {
> die("Can't forward port 0 for option '-%c %s'",
> @@ -185,23 +185,23 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
> fwd->delta[i] = to - first;
>
> if (optname == 't')
> - ret = tcp_listen(c, PIF_HOST, addr, ifname, i);
> + fd = tcp_listen(c, PIF_HOST, addr, ifname, i);
> else if (optname == 'u')
> - ret = udp_listen(c, PIF_HOST, addr, ifname, i);
> + fd = udp_listen(c, PIF_HOST, addr, ifname, i);
> else
> /* No way to check in advance for -T and -U */
> - ret = 0;
> + fd = 0;
>
> - if (ret == -ENFILE || ret == -EMFILE) {
> + if (fd == -ENFILE || fd == -EMFILE) {
> die("Can't open enough sockets for port specifier: %s",
> optarg);
> }
>
> - if (!ret) {
> + if (fd >= 0) {
> bound_one = true;
> } else if (!weak) {
> die("Failed to bind port %u (%s) for option '-%c %s'",
> - i, strerror_(-ret), optname, optarg);
> + i, strerror_(-fd), optname, optarg);
> }
> }
>
> diff --git a/tcp.c b/tcp.c
> index 67007c05..80b47f3c 100644
> --- a/tcp.c
> +++ b/tcp.c
> @@ -2680,7 +2680,7 @@ void tcp_sock_handler(const struct ctx *c, union epoll_ref ref,
> * @ifname: Name of interface to bind to, NULL for any
> * @port: Port, host order
> *
> - * Return: 0 on success, negative error code on failure
> + * Return: Socket fd on success, negative error code on failure
Nit, here and on udp_listen(): "socket". See also 9e0423e13541 ("style:
Fix 'Return' comment style").
> */
> int tcp_listen(const struct ctx *c, uint8_t pif,
> const union inany_addr *addr, const char *ifname, in_port_t port)
> @@ -2729,10 +2729,7 @@ int tcp_listen(const struct ctx *c, uint8_t pif,
> socks[port][V6] = s < 0 ? -1 : s;
> }
>
> - if (s < 0)
> - return s;
> -
> - return 0;
> + return s;
> }
>
> /**
> diff --git a/udp.c b/udp.c
> index 8cfa1e1f..63dc7c25 100644
> --- a/udp.c
> +++ b/udp.c
> @@ -1136,7 +1136,7 @@ int udp_tap_handler(const struct ctx *c, uint8_t pif,
> * @ifname: Name of interface to bind to, NULL if not configured
> * @port: Port, host order
> *
> - * Return: 0 on success, negative error code on failure
> + * Return: Socket fd on success, negative error code on failure
> */
> int udp_listen(const struct ctx *c, uint8_t pif,
> const union inany_addr *addr, const char *ifname, in_port_t port)
> @@ -1180,7 +1180,7 @@ int udp_listen(const struct ctx *c, uint8_t pif,
> if (!addr || !inany_v4(addr))
> socks[V6][port] = s < 0 ? -1 : s;
>
> - return s < 0 ? s : 0;
> + return s;
> }
>
> /**
--
Stefano
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing
2026-01-10 23:33 ` Stefano Brivio
@ 2026-01-12 3:42 ` David Gibson
2026-01-13 0:12 ` Stefano Brivio
0 siblings, 1 reply; 15+ messages in thread
From: David Gibson @ 2026-01-12 3:42 UTC (permalink / raw)
To: Stefano Brivio; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 6949 bytes --]
On Sun, Jan 11, 2026 at 12:33:14AM +0100, Stefano Brivio wrote:
> On Mon, 5 Jan 2026 19:28:48 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > We need to support (as best we can) older kernels which don't allow
> > unprivilieged processes to use the SO_BINDTODEVICE socket option.
>
> Nit: unprivileged
>
> > Fallcaks for that case are controlled by the c->no_bindtodevice variable.
>
> Fallbacks
Oops & oops. Fixed.
> > Currently testing behaviour of those fallbacks requires setting up a test
> > system with a kernel that doesn't support the option, which is pretty
> > awkward. We can test it almost as well and much more easily by adding a
> > command line option to explicitly disable use of SO_BINDTODEVICE.
>
> It's kind of hard to understand if this patch entirely does that, I
> think.
Well, it forces c->no_bindtodevice to be true. If we attempt to use
SO_BINDTODEVICE in that case, it's a bug elsewhere.
> We still have a separate, implicit probing of SO_BINDTODEVICE in
> sock_l4_(), which is perhaps excluded by c->no_bindtodevice (but then
> the comment is misleading?).
It should indeed be excluded because we should never call sock_l4_()
with a non-empty ifname if !c->no_bindtodevice. It's not really
probing, because we outright fail sock_l4_(), there's no fallback
there. The error path is there:
* As a backstop if there is a bug elsewhere meaning we do call this
with non-empty ifname
* If the SO_BINDTODEVICE call fails for a reason other than being
globally unavailable (non existent interface, out of memory,
sufficiently perverse selinux module).
Given the above, probably should be an err(), and the comment there is
no longer accurate / helpful (we already moved it to
sock_probe_features()). I've made those changes for the next spin.
> > Like --no-splice this is envisaged as something for developers' and
> > testers' convenience, not a supported option for end users. The man page
> > text reflects that.
>
> I never really understood the point of --no-splice, as there was no
> user request whatsoever behind it, but fine, the argument was that it
> added some needed functionality, even though I couldn't quite grasp
> which one it was.
That was never the argument from _me_ for --no-splice. For me it was
always that it was useful for development / testing / debugging, not
that it was (directly) useful to end users. That's true in at least
two ways:
* Allows testing non-splice functionality without having to either
use passt or create some non-loopback addresses
* Lets us ask a user reporting a problem to try --no-splice if we
suspect, but aren't sure that it's specific to the splice logic
My case for --no-bindtodevice is the same: it's useful to me (and
therefore I'm guessing to other developers and testers). The man page
update is pretty explicit about that.
> However, with this, the question is where we draw the line. There are
> probably other options we could use to make debugging or testing
> slightly simpler, but if they don't offer actual functionality, we
> always kept them out so far.
I mean, maybe, none are immediately occurring to me. If they do in
future, I think we should consider adding them. Note that
--no-splice, and especially --no-bindtodevice are extremely simple to
implement. I would not be arguing for them if they were more complex.
> That's because we already have a long list of options and making it
> unnecessarily longer is a disservice to users, I think.
That's a valid point. Would it be more palatable to you if we made
these suboptions of some explicit "developer hacks" option? (--hacks?
--debugopt? --devtest?)
> Would using something like this:
>
> sed -i 's/(\(setsockopt([a-z]*, SOL_SOCKET, SO_BINDTODEVICE\)/((errno = EPERM) || \1/g' *.c
>
> be totally outrageous, for testing purposes?
Totally outrageous, no. A bit more hassle, yes.
> It has the advantage of making it easier to verify if we're really
> disabling the usage of SO_BINDTODEVICE on all the paths (together with
> grep / git / editors), and not introducing additional command line
> options.
>
> Another trick I use sometimes to selectively disable or enable kernel
> features is to handle system calls via seitan, in this case the
> (simple) recipe would something like:
>
> [
> {
> "match": [
> { "setsockopt": { "level": socket", "name": "bindtodevice" } }
> ],
> "return": { "value": "EPERM", "error": -1 }
> }
> ]
>
> but I haven't implemented setsockopt() yet. :(
>
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> > conf.c | 2 ++
> > passt.1 | 6 ++++++
> > 2 files changed, 8 insertions(+)
> >
> > diff --git a/conf.c b/conf.c
> > index ceb9aa55..70ea168c 100644
> > --- a/conf.c
> > +++ b/conf.c
> > @@ -962,6 +962,7 @@ static void usage(const char *name, FILE *f, int status)
> > " --no-ndp Disable NDP responses\n"
> > " --no-dhcpv6 Disable DHCPv6 server\n"
> > " --no-ra Disable router advertisements\n"
> > + " --no-bindtodevice Disable SO_BINDTODEVICE\n"
> > " --freebind Bind to any address for forwarding\n"
> > " --no-map-gw Don't map gateway address to host\n"
> > " -4, --ipv4-only Enable IPv4 operation only\n"
> > @@ -1454,6 +1455,7 @@ void conf(struct ctx *c, int argc, char **argv)
> > {"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 },
> > {"no-ndp", no_argument, &c->no_ndp, 1 },
> > {"no-ra", no_argument, &c->no_ra, 1 },
> > + {"no-bindtodevice", no_argument, &c->no_bindtodevice, 1},
> > {"no-splice", no_argument, &c->no_splice, 1 },
> > {"freebind", no_argument, &c->freebind, 1 },
> > {"no-map-gw", no_argument, &no_map_gw, 1 },
> > diff --git a/passt.1 b/passt.1
> > index db0d6620..4859d9e5 100644
> > --- a/passt.1
> > +++ b/passt.1
> > @@ -348,6 +348,12 @@ namespace will be silently dropped.
> > Disable Router Advertisements. Router Solicitations coming from guest or target
> > namespace will be ignored.
> >
> > +.TP
> > +.BR \-\-no-bindtodevice
> > +Development/testing option, do not use. Disables use of
> > +SO_BINDTODEVICE socket option. Implicitly enabled on older kernels
> > +which don't permit unprivileged use of SO_BINDTODEVICE.
> > +
> > .TP
> > .BR \-\-freebind
> > Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
>
> The change looks otherwise good to me... I just hope we can avoid it
> somehow, but if not, so be it.
I mean, it's not essential to anything that follows, but it was useful
to me during testing. If you really don't want it, well, I'll cope.
--
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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions
2026-01-10 23:33 ` Stefano Brivio
@ 2026-01-12 3:48 ` David Gibson
2026-01-13 0:12 ` Stefano Brivio
0 siblings, 1 reply; 15+ messages in thread
From: David Gibson @ 2026-01-12 3:48 UTC (permalink / raw)
To: Stefano Brivio; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 4771 bytes --]
On Sun, Jan 11, 2026 at 12:33:28AM +0100, Stefano Brivio wrote:
> On Mon, 5 Jan 2026 19:28:49 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > Currently, it's possible to explicitly ask for forwarding from an IPv4
> > address, while disabling IPv4:
> > $ pasta -t 192.0.2.1/12345 -6
> > or vice versa:
> > $ pasta -t 2001:db8::1/12345 -4
> >
> > Currently, the impossible to implement forwarding option will be silently
> > ignored. That's potentially confusing since in a complex setup, it might
> > not be obvious why the requested forward isn't taking effect.
> >
> > Specifically, it's ignored at a fairly low level: tcp_listen() and
> > udp_listen() ignore it and return 0. Those run kind of late to give a
> > good error message. Change the low-level functions to return -EACCES
> > (chosen because that's what the kernel will return if you request IPv6
> > when it's disabled by sysctl).
>
> I couldn't quite find out in which case EACCES is returned by the
> kernel. If I set /proc/sys/net/ipv6/conf/all/disable_ipv6 to 1 and then
> bind() an IPv6 address, after setting IPV6_FREEBIND, I get 0.
Huh. EAFNOSUPPORT seems like it makes more sense, but oddly didn't
spot it. I was looking at:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/addrconf.c#n1098
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/addrconf.c#n2565
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/route.c#n3664
Happy enough to change it to EAFNOSUPPORT if you'd prefer.
> If I disable IPv6 via command line (ipv6.disable=1) I get EAFNOSUPPORT
> on bind(), and EOPNOTSUPP on setting addresses and routes. EACCES, I
> couldn't quite spot it yet.
Huh. Kind of weird it only fails on bind(), not on socket().
> > Most callers of {tcp,udp}_listen() ignore
> > the return code, so this is a no-op for them. In the remaining caller,
> > conf_ports_range_except() check for the case explicitly, and provide a
> > meaningful error message.
> >
> > Of itself, this bug is insignificant, but this is a roadblock to having
> > {tcp,udp}_listen() return socket fds, which in turn is a roadblock to my
> > flexible forwarding work. So, might as well fix it.
> >
> > Link: https://bugs.passt.top/show_bug.cgi?id=186
> >
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> > conf.c | 10 ++++++++++
> > tcp.c | 6 ++----
> > udp.c | 6 ++----
> > 3 files changed, 14 insertions(+), 8 deletions(-)
> >
> > diff --git a/conf.c b/conf.c
> > index 70ea168c..cc3c20a9 100644
> > --- a/conf.c
> > +++ b/conf.c
> > @@ -162,6 +162,16 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
> > optname, optarg);
> > }
> >
> > + if (addr) {
> > + if (!c->ifi4 && inany_v4(addr)) {
> > + die("IPv4 is disabled, can't use -%c %s",
> > + optname, optarg);
> > + } else if (!c->ifi6 && !inany_v4(addr)) {
> > + die("IPv6 is disabled, can't use -%c %s",
> > + optname, optarg);
> > + }
> > + }
> > +
> > for (i = first; i <= last; i++) {
> > if (bitmap_isset(exclude, i))
> > continue;
> > diff --git a/tcp.c b/tcp.c
> > index e7fa85f3..67007c05 100644
> > --- a/tcp.c
> > +++ b/tcp.c
> > @@ -2700,16 +2700,14 @@ int tcp_listen(const struct ctx *c, uint8_t pif,
> > /* Restrict to v6 only */
> > addr = &inany_any6;
> > else if (inany_v4(addr))
> > - /* Nothing to do */
> > - return 0;
> > + return -EACCES;
> > }
> > if (!c->ifi6) {
> > if (!addr)
> > /* Restrict to v4 only */
> > addr = &inany_any4;
> > else if (!inany_v4(addr))
> > - /* Nothing to do */
> > - return 0;
> > + return -EACCES;
> > }
> >
> > if (pif == PIF_HOST) {
> > diff --git a/udp.c b/udp.c
> > index eda55c39..8cfa1e1f 100644
> > --- a/udp.c
> > +++ b/udp.c
> > @@ -1162,16 +1162,14 @@ int udp_listen(const struct ctx *c, uint8_t pif,
> > /* Restrict to v6 only */
> > addr = &inany_any6;
> > else if (inany_v4(addr))
> > - /* Nothing to do */
> > - return 0;
> > + return -EACCES;
> > }
> > if (!c->ifi6) {
> > if (!addr)
> > /* Restrict to v4 only */
> > addr = &inany_any4;
> > else if (!inany_v4(addr))
> > - /* Nothing to do */
> > - return 0;
> > + return -EACCES;
> > }
> >
> > s = pif_sock_l4(c, EPOLL_TYPE_UDP_LISTEN, pif,
>
> The rest looks good to me.
>
> --
> Stefano
>
--
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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds
2026-01-10 23:33 ` Stefano Brivio
@ 2026-01-12 3:50 ` David Gibson
0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2026-01-12 3:50 UTC (permalink / raw)
To: Stefano Brivio; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 2852 bytes --]
On Sun, Jan 11, 2026 at 12:33:39AM +0100, Stefano Brivio wrote:
> On Mon, 5 Jan 2026 19:28:50 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > {tcp,udp}_listen() currently return 0 on success, rather than the socket
> > fd they created. Historically, that was because these functions could
> > sometimes create multiple sockets. We've now refactored things to avoid
> > that, so it makes more sense for them to return the socket on success.
> >
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> > conf.c | 14 +++++++-------
> > tcp.c | 7 ++-----
> > udp.c | 4 ++--
> > 3 files changed, 11 insertions(+), 14 deletions(-)
> >
> > diff --git a/conf.c b/conf.c
> > index cc3c20a9..5db49653 100644
> > --- a/conf.c
> > +++ b/conf.c
> > @@ -149,7 +149,7 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
> > {
> > bool bound_one = false;
> > unsigned i;
> > - int ret;
> > + int fd;
> >
> > if (first == 0) {
> > die("Can't forward port 0 for option '-%c %s'",
> > @@ -185,23 +185,23 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
> > fwd->delta[i] = to - first;
> >
> > if (optname == 't')
> > - ret = tcp_listen(c, PIF_HOST, addr, ifname, i);
> > + fd = tcp_listen(c, PIF_HOST, addr, ifname, i);
> > else if (optname == 'u')
> > - ret = udp_listen(c, PIF_HOST, addr, ifname, i);
> > + fd = udp_listen(c, PIF_HOST, addr, ifname, i);
> > else
> > /* No way to check in advance for -T and -U */
> > - ret = 0;
> > + fd = 0;
> >
> > - if (ret == -ENFILE || ret == -EMFILE) {
> > + if (fd == -ENFILE || fd == -EMFILE) {
> > die("Can't open enough sockets for port specifier: %s",
> > optarg);
> > }
> >
> > - if (!ret) {
> > + if (fd >= 0) {
> > bound_one = true;
> > } else if (!weak) {
> > die("Failed to bind port %u (%s) for option '-%c %s'",
> > - i, strerror_(-ret), optname, optarg);
> > + i, strerror_(-fd), optname, optarg);
> > }
> > }
> >
> > diff --git a/tcp.c b/tcp.c
> > index 67007c05..80b47f3c 100644
> > --- a/tcp.c
> > +++ b/tcp.c
> > @@ -2680,7 +2680,7 @@ void tcp_sock_handler(const struct ctx *c, union epoll_ref ref,
> > * @ifname: Name of interface to bind to, NULL for any
> > * @port: Port, host order
> > *
> > - * Return: 0 on success, negative error code on failure
> > + * Return: Socket fd on success, negative error code on failure
>
> Nit, here and on udp_listen(): "socket". See also 9e0423e13541 ("style:
> Fix 'Return' comment style").
Oops, fixed.
--
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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing
2026-01-12 3:42 ` David Gibson
@ 2026-01-13 0:12 ` Stefano Brivio
2026-01-13 3:00 ` David Gibson
0 siblings, 1 reply; 15+ messages in thread
From: Stefano Brivio @ 2026-01-13 0:12 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On Mon, 12 Jan 2026 14:42:39 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Sun, Jan 11, 2026 at 12:33:14AM +0100, Stefano Brivio wrote:
> > On Mon, 5 Jan 2026 19:28:48 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > We need to support (as best we can) older kernels which don't allow
> > > unprivilieged processes to use the SO_BINDTODEVICE socket option.
> >
> > Nit: unprivileged
> >
> > > Fallcaks for that case are controlled by the c->no_bindtodevice variable.
> >
> > Fallbacks
>
> Oops & oops. Fixed.
>
> > > Currently testing behaviour of those fallbacks requires setting up a test
> > > system with a kernel that doesn't support the option, which is pretty
> > > awkward. We can test it almost as well and much more easily by adding a
> > > command line option to explicitly disable use of SO_BINDTODEVICE.
> >
> > It's kind of hard to understand if this patch entirely does that, I
> > think.
>
> Well, it forces c->no_bindtodevice to be true. If we attempt to use
> SO_BINDTODEVICE in that case, it's a bug elsewhere.
Yes... but we wouldn't find it with this patch. We would only find it
with a kernel actually not supporting it, or by replacing all the
setsockopt() calls with something else.
> > We still have a separate, implicit probing of SO_BINDTODEVICE in
> > sock_l4_(), which is perhaps excluded by c->no_bindtodevice (but then
> > the comment is misleading?).
>
> It should indeed be excluded because we should never call sock_l4_()
> with a non-empty ifname if !c->no_bindtodevice. It's not really
> probing, because we outright fail sock_l4_(), there's no fallback
> there. The error path is there:
> * As a backstop if there is a bug elsewhere meaning we do call this
> with non-empty ifname
> * If the SO_BINDTODEVICE call fails for a reason other than being
> globally unavailable (non existent interface, out of memory,
> sufficiently perverse selinux module).
>
> Given the above, probably should be an err(), and the comment there is
> no longer accurate / helpful (we already moved it to
> sock_probe_features()). I've made those changes for the next spin.
Ah, okay.
> > > Like --no-splice this is envisaged as something for developers' and
> > > testers' convenience, not a supported option for end users. The man page
> > > text reflects that.
> >
> > I never really understood the point of --no-splice, as there was no
> > user request whatsoever behind it, but fine, the argument was that it
> > added some needed functionality, even though I couldn't quite grasp
> > which one it was.
>
> That was never the argument from _me_ for --no-splice. For me it was
> always that it was useful for development / testing / debugging, not
> that it was (directly) useful to end users.
Right, I think Jon meant it was useful to end users. Otherwise, I would
have argued, it should be mentioned in the man page, and, I would have
argued further, the option shouldn't exist at all.
> That's true in at least
> two ways:
> * Allows testing non-splice functionality without having to either
> use passt or create some non-loopback addresses
...but without a loopback address we can't use the tap path anyway.
> * Lets us ask a user reporting a problem to try --no-splice if we
> suspect, but aren't sure that it's specific to the splice logic
...which we never had to do (because it's obvious whether they're using
the splice logic or not, I simply ask what kind of address they're
using).
> My case for --no-bindtodevice is the same: it's useful to me (and
> therefore I'm guessing to other developers and testers).
I have some doubts about other developers and testers, in the sense
that to me it really looks like something you need just for the
implementation.
> The man page update is pretty explicit about that.
Sure, better than --no-splice.
> > However, with this, the question is where we draw the line. There are
> > probably other options we could use to make debugging or testing
> > slightly simpler, but if they don't offer actual functionality, we
> > always kept them out so far.
>
> I mean, maybe, none are immediately occurring to me. If they do in
> future, I think we should consider adding them.
The thing is, 'passt -h' already reports 117 lines. It's still somewhat
usable, but 200 lines would be substantially less usable, I think.
A counter-example (at least for me) is 'qemu-system-x86_64 -h', 524
lines on my build. I don't think that's usable and I don't think we
should go there.
> Note that
> --no-splice, and especially --no-bindtodevice are extremely simple to
> implement. I would not be arguing for them if they were more complex.
My concern isn't really about complexity of the implementation, rather
about the fact that we add more command line options. Users don't need
them, but they have to scroll through them (in --help output and man
page) just because we needed them (quite likely) once.
> > That's because we already have a long list of options and making it
> > unnecessarily longer is a disservice to users, I think.
>
> That's a valid point. Would it be more palatable to you if we made
> these suboptions of some explicit "developer hacks" option? (--hacks?
> --debugopt? --devtest?)
At that point the hassle looks comparable to a mandatory macro
implementing (or not) the setsockopt(), which can be selected at build
time.
But anyway, not really, because they would also need to be documented
command-line options. How would we use them otherwise as developers?
> > Would using something like this:
> >
> > sed -i 's/(\(setsockopt([a-z]*, SOL_SOCKET, SO_BINDTODEVICE\)/((errno = EPERM) || \1/g' *.c
> >
> > be totally outrageous, for testing purposes?
>
> Totally outrageous, no. A bit more hassle, yes.
...what about a script? Or a macro with a #define?
> > It has the advantage of making it easier to verify if we're really
> > disabling the usage of SO_BINDTODEVICE on all the paths (together with
> > grep / git / editors), and not introducing additional command line
> > options.
> >
> > Another trick I use sometimes to selectively disable or enable kernel
> > features is to handle system calls via seitan, in this case the
> > (simple) recipe would something like:
> >
> > [
> > {
> > "match": [
> > { "setsockopt": { "level": socket", "name": "bindtodevice" } }
> > ],
> > "return": { "value": "EPERM", "error": -1 }
> > }
> > ]
> >
> > but I haven't implemented setsockopt() yet. :(
> >
> > > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > > ---
> > > conf.c | 2 ++
> > > passt.1 | 6 ++++++
> > > 2 files changed, 8 insertions(+)
> > >
> > > diff --git a/conf.c b/conf.c
> > > index ceb9aa55..70ea168c 100644
> > > --- a/conf.c
> > > +++ b/conf.c
> > > @@ -962,6 +962,7 @@ static void usage(const char *name, FILE *f, int status)
> > > " --no-ndp Disable NDP responses\n"
> > > " --no-dhcpv6 Disable DHCPv6 server\n"
> > > " --no-ra Disable router advertisements\n"
> > > + " --no-bindtodevice Disable SO_BINDTODEVICE\n"
> > > " --freebind Bind to any address for forwarding\n"
> > > " --no-map-gw Don't map gateway address to host\n"
> > > " -4, --ipv4-only Enable IPv4 operation only\n"
> > > @@ -1454,6 +1455,7 @@ void conf(struct ctx *c, int argc, char **argv)
> > > {"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 },
> > > {"no-ndp", no_argument, &c->no_ndp, 1 },
> > > {"no-ra", no_argument, &c->no_ra, 1 },
> > > + {"no-bindtodevice", no_argument, &c->no_bindtodevice, 1},
> > > {"no-splice", no_argument, &c->no_splice, 1 },
> > > {"freebind", no_argument, &c->freebind, 1 },
> > > {"no-map-gw", no_argument, &no_map_gw, 1 },
> > > diff --git a/passt.1 b/passt.1
> > > index db0d6620..4859d9e5 100644
> > > --- a/passt.1
> > > +++ b/passt.1
> > > @@ -348,6 +348,12 @@ namespace will be silently dropped.
> > > Disable Router Advertisements. Router Solicitations coming from guest or target
> > > namespace will be ignored.
> > >
> > > +.TP
> > > +.BR \-\-no-bindtodevice
> > > +Development/testing option, do not use. Disables use of
> > > +SO_BINDTODEVICE socket option. Implicitly enabled on older kernels
> > > +which don't permit unprivileged use of SO_BINDTODEVICE.
> > > +
> > > .TP
> > > .BR \-\-freebind
> > > Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
> >
> > The change looks otherwise good to me... I just hope we can avoid it
> > somehow, but if not, so be it.
>
> I mean, it's not essential to anything that follows, but it was useful
> to me during testing. If you really don't want it, well, I'll cope.
I'm not sure but... if the threshold is "useful during testing" we
should also build something reordering TCP segments so that we can
reproduce https://bugs.passt.top/show_bug.cgi?id=159 from time to time.
And that could actually be a clean and relatively simple implementation,
but it just adds noise to the documentation.
I don't see a big damage we do with two extra options, but... then
maybe we should we stop at 5? 10?
--
Stefano
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions
2026-01-12 3:48 ` David Gibson
@ 2026-01-13 0:12 ` Stefano Brivio
2026-01-13 3:05 ` David Gibson
0 siblings, 1 reply; 15+ messages in thread
From: Stefano Brivio @ 2026-01-13 0:12 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On Mon, 12 Jan 2026 14:48:54 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Sun, Jan 11, 2026 at 12:33:28AM +0100, Stefano Brivio wrote:
> > On Mon, 5 Jan 2026 19:28:49 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > Currently, it's possible to explicitly ask for forwarding from an IPv4
> > > address, while disabling IPv4:
> > > $ pasta -t 192.0.2.1/12345 -6
> > > or vice versa:
> > > $ pasta -t 2001:db8::1/12345 -4
> > >
> > > Currently, the impossible to implement forwarding option will be silently
> > > ignored. That's potentially confusing since in a complex setup, it might
> > > not be obvious why the requested forward isn't taking effect.
> > >
> > > Specifically, it's ignored at a fairly low level: tcp_listen() and
> > > udp_listen() ignore it and return 0. Those run kind of late to give a
> > > good error message. Change the low-level functions to return -EACCES
> > > (chosen because that's what the kernel will return if you request IPv6
> > > when it's disabled by sysctl).
> >
> > I couldn't quite find out in which case EACCES is returned by the
> > kernel. If I set /proc/sys/net/ipv6/conf/all/disable_ipv6 to 1 and then
> > bind() an IPv6 address, after setting IPV6_FREEBIND, I get 0.
>
> Huh. EAFNOSUPPORT seems like it makes more sense, but oddly didn't
> spot it. I was looking at:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/addrconf.c#n1098
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/addrconf.c#n2565
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/route.c#n3664
Weird, I guess it eventually gets translated to EOPNOTSUPP later
(perhaps in netlink code), because:
# strace ip addr add db8::1 dev ens3
[...]
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=84, nlmsg_type=NLMSG_ERROR, nlmsg_flags=0, nlmsg_seq=1768262003, nlmsg_pid=1598}, {error=-EOPNOTSUPP, msg=[{nlmsg_len=64, nlmsg_type=RTM_NEWADDR, nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, nlmsg_seq=1768262003, nlmsg_pid=0}, {ifa_family=AF_INET6, ifa_prefixlen=128, ifa_flags=0, ifa_scope=RT_SCOPE_UNIVERSE, ifa_index=if_nametoindex("ens3")}, [[{nla_len=20, nla_type=IFA_LOCAL}, inet_pton(AF_INET6, "db8::1")], [{nla_len=20, nla_type=IFA_ADDRESS}, inet_pton(AF_INET6, "db8::1")]]]}], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 84
write(2, "RTNETLINK answers: Operation not"..., 43RTNETLINK answers: Operation not supported
it's EOPNOTSUPP in the NLMSG_ERROR message.
> Happy enough to change it to EAFNOSUPPORT if you'd prefer.
I think it would make a lot more sense, EACCES would confuse pretty
much anybody (and I can't get the kernel to return that over netlink
anyway).
> > If I disable IPv6 via command line (ipv6.disable=1) I get EAFNOSUPPORT
> > on bind(), and EOPNOTSUPP on setting addresses and routes. EACCES, I
> > couldn't quite spot it yet.
>
> Huh. Kind of weird it only fails on bind(), not on socket().
Oops, I was fooled by the error message we print in that case. It
actually fails on socket():
socket(AF_INET6, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = -1 EAFNOSUPPORT (Address family not supported by protocol)
but we print:
L4 socket: Address family not supported by protocol
Failed to bind port 2548 (Address family not supported by protocol) for option '-t 2b8::1/2548'
which makes sense because that's what we're doing with that port (just
not with that socket).
--
Stefano
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing
2026-01-13 0:12 ` Stefano Brivio
@ 2026-01-13 3:00 ` David Gibson
2026-01-13 22:13 ` Stefano Brivio
0 siblings, 1 reply; 15+ messages in thread
From: David Gibson @ 2026-01-13 3:00 UTC (permalink / raw)
To: Stefano Brivio; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 11180 bytes --]
On Tue, Jan 13, 2026 at 01:12:01AM +0100, Stefano Brivio wrote:
> On Mon, 12 Jan 2026 14:42:39 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Sun, Jan 11, 2026 at 12:33:14AM +0100, Stefano Brivio wrote:
> > > On Mon, 5 Jan 2026 19:28:48 +1100
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > > We need to support (as best we can) older kernels which don't allow
> > > > unprivilieged processes to use the SO_BINDTODEVICE socket option.
> > >
> > > Nit: unprivileged
> > >
> > > > Fallcaks for that case are controlled by the c->no_bindtodevice variable.
> > >
> > > Fallbacks
> >
> > Oops & oops. Fixed.
> >
> > > > Currently testing behaviour of those fallbacks requires setting up a test
> > > > system with a kernel that doesn't support the option, which is pretty
> > > > awkward. We can test it almost as well and much more easily by adding a
> > > > command line option to explicitly disable use of SO_BINDTODEVICE.
> > >
> > > It's kind of hard to understand if this patch entirely does that, I
> > > think.
> >
> > Well, it forces c->no_bindtodevice to be true. If we attempt to use
> > SO_BINDTODEVICE in that case, it's a bug elsewhere.
>
> Yes... but we wouldn't find it with this patch. We would only find it
> with a kernel actually not supporting it, or by replacing all the
> setsockopt() calls with something else.
True. What I was looking to test with this was behaviour of the
higher level workarounds - e.g. that we split -[TU] forwards into
127.0.0.1 and ::1 instead of using *%lo.
> > > We still have a separate, implicit probing of SO_BINDTODEVICE in
> > > sock_l4_(), which is perhaps excluded by c->no_bindtodevice (but then
> > > the comment is misleading?).
> >
> > It should indeed be excluded because we should never call sock_l4_()
> > with a non-empty ifname if !c->no_bindtodevice. It's not really
> > probing, because we outright fail sock_l4_(), there's no fallback
> > there. The error path is there:
> > * As a backstop if there is a bug elsewhere meaning we do call this
> > with non-empty ifname
> > * If the SO_BINDTODEVICE call fails for a reason other than being
> > globally unavailable (non existent interface, out of memory,
> > sufficiently perverse selinux module).
> >
> > Given the above, probably should be an err(), and the comment there is
> > no longer accurate / helpful (we already moved it to
> > sock_probe_features()). I've made those changes for the next spin.
>
> Ah, okay.
>
> > > > Like --no-splice this is envisaged as something for developers' and
> > > > testers' convenience, not a supported option for end users. The man page
> > > > text reflects that.
> > >
> > > I never really understood the point of --no-splice, as there was no
> > > user request whatsoever behind it, but fine, the argument was that it
> > > added some needed functionality, even though I couldn't quite grasp
> > > which one it was.
> >
> > That was never the argument from _me_ for --no-splice. For me it was
> > always that it was useful for development / testing / debugging, not
> > that it was (directly) useful to end users.
>
> Right, I think Jon meant it was useful to end users. Otherwise, I would
> have argued, it should be mentioned in the man page, and, I would have
> argued further, the option shouldn't exist at all.
>
> > That's true in at least
> > two ways:
> > * Allows testing non-splice functionality without having to either
> > use passt or create some non-loopback addresses
>
> ...but without a loopback address we can't use the tap path anyway.
I'm not sure what you mean here. If I want to exercise something on
the tap path I can use:
$ pasta --no-splice [whatever else]
[...]
$ socat STDIO TCP:localhost:12345
and I don't need to look up my host's current global IP. Or if I want
to test tap with multiple different host-side oaddrs, I can use
127.0.0.0/8 without
> > * Lets us ask a user reporting a problem to try --no-splice if we
> > suspect, but aren't sure that it's specific to the splice logic
>
> ...which we never had to do (because it's obvious whether they're using
> the splice logic or not, I simply ask what kind of address they're
> using).
Admittedly, I don't think we've ever used it like that since it was
introduced. I do know that before it existed there were several bugs
where it would have been helpful (obviously not essential) to try
that.
> > My case for --no-bindtodevice is the same: it's useful to me (and
> > therefore I'm guessing to other developers and testers).
>
> I have some doubts about other developers and testers, in the sense
> that to me it really looks like something you need just for the
> implementation.
Eh, maybe.
> > The man page update is pretty explicit about that.
>
> Sure, better than --no-splice.
>
> > > However, with this, the question is where we draw the line. There are
> > > probably other options we could use to make debugging or testing
> > > slightly simpler, but if they don't offer actual functionality, we
> > > always kept them out so far.
> >
> > I mean, maybe, none are immediately occurring to me. If they do in
> > future, I think we should consider adding them.
>
> The thing is, 'passt -h' already reports 117 lines. It's still somewhat
> usable, but 200 lines would be substantially less usable, I think.
>
> A counter-example (at least for me) is 'qemu-system-x86_64 -h', 524
> lines on my build. I don't think that's usable and I don't think we
> should go there.
>
> > Note that
> > --no-splice, and especially --no-bindtodevice are extremely simple to
> > implement. I would not be arguing for them if they were more complex.
>
> My concern isn't really about complexity of the implementation, rather
> about the fact that we add more command line options. Users don't need
> them, but they have to scroll through them (in --help output and man
> page) just because we needed them (quite likely) once.
That's a reasonable point.
> > > That's because we already have a long list of options and making it
> > > unnecessarily longer is a disservice to users, I think.
> >
> > That's a valid point. Would it be more palatable to you if we made
> > these suboptions of some explicit "developer hacks" option? (--hacks?
> > --debugopt? --devtest?)
>
> At that point the hassle looks comparable to a mandatory macro
> implementing (or not) the setsockopt(), which can be selected at build
> time.
True, a build time option might do almost as well.
> But anyway, not really, because they would also need to be documented
> command-line options. How would we use them otherwise as developers?
Well, we could limit --help and the man page to just stating the
existence of the top-level option and a pointer to a HACKS.md or
whatever for the details. And we could make it explicitly subject to
change without notice between versions.
> > > Would using something like this:
> > >
> > > sed -i 's/(\(setsockopt([a-z]*, SOL_SOCKET, SO_BINDTODEVICE\)/((errno = EPERM) || \1/g' *.c
> > >
> > > be totally outrageous, for testing purposes?
> >
> > Totally outrageous, no. A bit more hassle, yes.
>
> ...what about a script? Or a macro with a #define?
>
> > > It has the advantage of making it easier to verify if we're really
> > > disabling the usage of SO_BINDTODEVICE on all the paths (together with
> > > grep / git / editors), and not introducing additional command line
> > > options.
> > >
> > > Another trick I use sometimes to selectively disable or enable kernel
> > > features is to handle system calls via seitan, in this case the
> > > (simple) recipe would something like:
> > >
> > > [
> > > {
> > > "match": [
> > > { "setsockopt": { "level": socket", "name": "bindtodevice" } }
> > > ],
> > > "return": { "value": "EPERM", "error": -1 }
> > > }
> > > ]
> > >
> > > but I haven't implemented setsockopt() yet. :(
> > >
> > > > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > > > ---
> > > > conf.c | 2 ++
> > > > passt.1 | 6 ++++++
> > > > 2 files changed, 8 insertions(+)
> > > >
> > > > diff --git a/conf.c b/conf.c
> > > > index ceb9aa55..70ea168c 100644
> > > > --- a/conf.c
> > > > +++ b/conf.c
> > > > @@ -962,6 +962,7 @@ static void usage(const char *name, FILE *f, int status)
> > > > " --no-ndp Disable NDP responses\n"
> > > > " --no-dhcpv6 Disable DHCPv6 server\n"
> > > > " --no-ra Disable router advertisements\n"
> > > > + " --no-bindtodevice Disable SO_BINDTODEVICE\n"
> > > > " --freebind Bind to any address for forwarding\n"
> > > > " --no-map-gw Don't map gateway address to host\n"
> > > > " -4, --ipv4-only Enable IPv4 operation only\n"
> > > > @@ -1454,6 +1455,7 @@ void conf(struct ctx *c, int argc, char **argv)
> > > > {"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 },
> > > > {"no-ndp", no_argument, &c->no_ndp, 1 },
> > > > {"no-ra", no_argument, &c->no_ra, 1 },
> > > > + {"no-bindtodevice", no_argument, &c->no_bindtodevice, 1},
> > > > {"no-splice", no_argument, &c->no_splice, 1 },
> > > > {"freebind", no_argument, &c->freebind, 1 },
> > > > {"no-map-gw", no_argument, &no_map_gw, 1 },
> > > > diff --git a/passt.1 b/passt.1
> > > > index db0d6620..4859d9e5 100644
> > > > --- a/passt.1
> > > > +++ b/passt.1
> > > > @@ -348,6 +348,12 @@ namespace will be silently dropped.
> > > > Disable Router Advertisements. Router Solicitations coming from guest or target
> > > > namespace will be ignored.
> > > >
> > > > +.TP
> > > > +.BR \-\-no-bindtodevice
> > > > +Development/testing option, do not use. Disables use of
> > > > +SO_BINDTODEVICE socket option. Implicitly enabled on older kernels
> > > > +which don't permit unprivileged use of SO_BINDTODEVICE.
> > > > +
> > > > .TP
> > > > .BR \-\-freebind
> > > > Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
> > >
> > > The change looks otherwise good to me... I just hope we can avoid it
> > > somehow, but if not, so be it.
> >
> > I mean, it's not essential to anything that follows, but it was useful
> > to me during testing. If you really don't want it, well, I'll cope.
>
> I'm not sure but... if the threshold is "useful during testing" we
> should also build something reordering TCP segments so that we can
> reproduce https://bugs.passt.top/show_bug.cgi?id=159 from time to time.
>
> And that could actually be a clean and relatively simple implementation,
> but it just adds noise to the documentation.
>
> I don't see a big damage we do with two extra options, but... then
> maybe we should we stop at 5? 10?
Hrm, yeah. Ok, you convinced me for now, I'll drop this one.
--
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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions
2026-01-13 0:12 ` Stefano Brivio
@ 2026-01-13 3:05 ` David Gibson
0 siblings, 0 replies; 15+ messages in thread
From: David Gibson @ 2026-01-13 3:05 UTC (permalink / raw)
To: Stefano Brivio; +Cc: passt-dev
[-- Attachment #1: Type: text/plain, Size: 4166 bytes --]
On Tue, Jan 13, 2026 at 01:12:06AM +0100, Stefano Brivio wrote:
> On Mon, 12 Jan 2026 14:48:54 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Sun, Jan 11, 2026 at 12:33:28AM +0100, Stefano Brivio wrote:
> > > On Mon, 5 Jan 2026 19:28:49 +1100
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > > Currently, it's possible to explicitly ask for forwarding from an IPv4
> > > > address, while disabling IPv4:
> > > > $ pasta -t 192.0.2.1/12345 -6
> > > > or vice versa:
> > > > $ pasta -t 2001:db8::1/12345 -4
> > > >
> > > > Currently, the impossible to implement forwarding option will be silently
> > > > ignored. That's potentially confusing since in a complex setup, it might
> > > > not be obvious why the requested forward isn't taking effect.
> > > >
> > > > Specifically, it's ignored at a fairly low level: tcp_listen() and
> > > > udp_listen() ignore it and return 0. Those run kind of late to give a
> > > > good error message. Change the low-level functions to return -EACCES
> > > > (chosen because that's what the kernel will return if you request IPv6
> > > > when it's disabled by sysctl).
> > >
> > > I couldn't quite find out in which case EACCES is returned by the
> > > kernel. If I set /proc/sys/net/ipv6/conf/all/disable_ipv6 to 1 and then
> > > bind() an IPv6 address, after setting IPV6_FREEBIND, I get 0.
> >
> > Huh. EAFNOSUPPORT seems like it makes more sense, but oddly didn't
> > spot it. I was looking at:
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/addrconf.c#n1098
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/addrconf.c#n2565
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/route.c#n3664
>
> Weird, I guess it eventually gets translated to EOPNOTSUPP later
> (perhaps in netlink code), because:
Yeah, I guess it must.
> # strace ip addr add db8::1 dev ens3
>
> [...]
>
> recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=84, nlmsg_type=NLMSG_ERROR, nlmsg_flags=0, nlmsg_seq=1768262003, nlmsg_pid=1598}, {error=-EOPNOTSUPP, msg=[{nlmsg_len=64, nlmsg_type=RTM_NEWADDR, nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, nlmsg_seq=1768262003, nlmsg_pid=0}, {ifa_family=AF_INET6, ifa_prefixlen=128, ifa_flags=0, ifa_scope=RT_SCOPE_UNIVERSE, ifa_index=if_nametoindex("ens3")}, [[{nla_len=20, nla_type=IFA_LOCAL}, inet_pton(AF_INET6, "db8::1")], [{nla_len=20, nla_type=IFA_ADDRESS}, inet_pton(AF_INET6, "db8::1")]]]}], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 84
> write(2, "RTNETLINK answers: Operation not"..., 43RTNETLINK answers: Operation not supported
>
> it's EOPNOTSUPP in the NLMSG_ERROR message.
Heh, that's a third option.
> > Happy enough to change it to EAFNOSUPPORT if you'd prefer.
>
> I think it would make a lot more sense, EACCES would confuse pretty
> much anybody (and I can't get the kernel to return that over netlink
> anyway).
Ok, done.
> > > If I disable IPv6 via command line (ipv6.disable=1) I get EAFNOSUPPORT
> > > on bind(), and EOPNOTSUPP on setting addresses and routes. EACCES, I
> > > couldn't quite spot it yet.
> >
> > Huh. Kind of weird it only fails on bind(), not on socket().
>
> Oops, I was fooled by the error message we print in that case. It
> actually fails on socket():
>
> socket(AF_INET6, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = -1 EAFNOSUPPORT (Address family not supported by protocol)
>
> but we print:
>
> L4 socket: Address family not supported by protocol
> Failed to bind port 2548 (Address family not supported by protocol) for option '-t 2b8::1/2548'
>
> which makes sense because that's what we're doing with that port (just
> not with that socket).
Ah, ok, that makes sense.
--
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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing
2026-01-13 3:00 ` David Gibson
@ 2026-01-13 22:13 ` Stefano Brivio
0 siblings, 0 replies; 15+ messages in thread
From: Stefano Brivio @ 2026-01-13 22:13 UTC (permalink / raw)
To: David Gibson; +Cc: passt-dev
On Tue, 13 Jan 2026 14:00:18 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:
> On Tue, Jan 13, 2026 at 01:12:01AM +0100, Stefano Brivio wrote:
> > On Mon, 12 Jan 2026 14:42:39 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> >
> > > On Sun, Jan 11, 2026 at 12:33:14AM +0100, Stefano Brivio wrote:
> > >
> > > > I never really understood the point of --no-splice, as there was no
> > > > user request whatsoever behind it, but fine, the argument was that it
> > > > added some needed functionality, even though I couldn't quite grasp
> > > > which one it was.
> > >
> > > That was never the argument from _me_ for --no-splice. For me it was
> > > always that it was useful for development / testing / debugging, not
> > > that it was (directly) useful to end users.
> >
> > Right, I think Jon meant it was useful to end users. Otherwise, I would
> > have argued, it should be mentioned in the man page, and, I would have
> > argued further, the option shouldn't exist at all.
> >
> > > That's true in at least
> > > two ways:
> > > * Allows testing non-splice functionality without having to either
> > > use passt or create some non-loopback addresses
> >
> > ...but without a loopback address we can't use the tap path anyway.
>
> I'm not sure what you mean here.
Oops, I meant to say "without a loopback address you can't use the
spliced path anyway".
> If I want to exercise something on
> the tap path I can use:
> $ pasta --no-splice [whatever else]
> [...]
> $ socat STDIO TCP:localhost:12345
>
> and I don't need to look up my host's current global IP.
Ah, right, sorry! That's the bit of functionality it actually adds. I
keep forgetting about it. This wasn't possible before.
--
Stefano
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-01-13 22:13 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-05 8:28 [PATCH 0/3] Allow listen functions to return fds David Gibson
2026-01-05 8:28 ` [PATCH 1/3] conf: Introduce --no-bindtodevice option for testing David Gibson
2026-01-10 23:33 ` Stefano Brivio
2026-01-12 3:42 ` David Gibson
2026-01-13 0:12 ` Stefano Brivio
2026-01-13 3:00 ` David Gibson
2026-01-13 22:13 ` Stefano Brivio
2026-01-05 8:28 ` [PATCH 2/3] tcp, udp, conf: Don't silently ignore listens on unsupported IP versions David Gibson
2026-01-10 23:33 ` Stefano Brivio
2026-01-12 3:48 ` David Gibson
2026-01-13 0:12 ` Stefano Brivio
2026-01-13 3:05 ` David Gibson
2026-01-05 8:28 ` [PATCH 3/3] tcp, udp: Make {tcp,udp}_listen() return socket fds David Gibson
2026-01-10 23:33 ` Stefano Brivio
2026-01-12 3:50 ` David Gibson
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).