From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>
Cc: passt-dev@passt.top, Andrea Bolognani <abologna@redhat.com>
Subject: Re: [PATCH] treewide: Sandbox qrap
Date: Sun, 19 Jul 2026 14:03:43 +1000 [thread overview]
Message-ID: <alxMmhYZ3Q0bArNU@gractus.seuss> (raw)
In-Reply-To: <20260718074225.1331134-1-sbrivio@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 39009 bytes --]
On Sat, Jul 18, 2026 at 09:42:25AM +0200, Stefano Brivio wrote:
> No sunsetting or rightsizing for you, qrap: dig, bury, and cover.
>
> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Hooray!
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> .gitignore | 1 -
> Makefile | 11 +-
> README.md | 4 -
> contrib/fedora/passt.spec | 2 -
> doc/demo.sh | 12 +-
> doc/passt_overview.excalidraw | 29 ---
> hooks/pre-push | 2 +-
> passt.1 | 235 ++++++++++---------
> qrap.1 | 77 ------
> qrap.c | 429 ----------------------------------
> tap.c | 2 -
> test/distro/opensuse | 2 +-
> 12 files changed, 127 insertions(+), 679 deletions(-)
> delete mode 100644 qrap.1
> delete mode 100644 qrap.c
>
> diff --git a/.gitignore b/.gitignore
> index 3e40d9f..71420b6 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -5,7 +5,6 @@
> /pasta.avx2
> /passt-repair
> /pesto
> -/qrap
> /pasta.1
> /seccomp.h
> /seccomp_pesto.h
> diff --git a/Makefile b/Makefile
> index 5757aef..77474d6 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -39,13 +39,12 @@ PASST_SRCS = arch.c arp.c bitmap.c checksum.c conf.c dhcp.c dhcpv6.c \
> parse.c passt.c pasta.c pcap.c pif.c repair.c serialise.c tap.c tcp.c \
> tcp_buf.c tcp_splice.c tcp_vu.c udp.c udp_flow.c udp_vu.c util.c \
> vhost_user.c virtio.c vu_common.c
> -QRAP_SRCS = qrap.c
> PASST_REPAIR_SRCS = passt-repair.c
> PESTO_SRCS = pesto.c bitmap.c fwd_rule.c inany.c ip.c lineread.c parse.c \
> serialise.c
> -SRCS = $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS)
> +SRCS = $(PASST_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS)
>
> -MANPAGES = passt.1 pasta.1 pesto.1 qrap.1 passt-repair.1
> +MANPAGES = passt.1 pasta.1 pesto.1 passt-repair.1
>
> PASST_HEADERS = arch.h arp.h bitmap.h checksum.h conf.h dhcp.h dhcpv6.h \
> epoll_ctl.h flow.h fwd.h fwd_rule.h flow_table.h icmp.h icmp_flow.h \
> @@ -54,7 +53,6 @@ PASST_HEADERS = arch.h arp.h bitmap.h checksum.h conf.h dhcp.h dhcpv6.h \
> serialise.h siphash.h tap.h tcp.h tcp_buf.h tcp_conn.h tcp_internal.h \
> tcp_splice.h tcp_vu.h udp.h udp_flow.h udp_internal.h udp_vu.h util.h \
> vhost_user.h virtio.h vu_common.h
> -QRAP_HEADERS = arp.h ip.h passt.h util.h
> PASST_REPAIR_HEADERS = linux_dep.h
> PESTO_HEADERS = bitmap.h common.h fwd_rule.h inany.h ip.h log.h parse.h \
> pesto.h serialise.h
> @@ -76,7 +74,7 @@ docdir ?= $(datarootdir)/doc/passt
> mandir ?= $(datarootdir)/man
> man1dir ?= $(mandir)/man1
>
> -BASEBIN := passt qrap passt-repair pesto
> +BASEBIN := passt passt-repair pesto
> ifeq ($(TARGET_ARCH),x86_64)
> BASEBIN += passt.avx2
> endif
> @@ -112,9 +110,6 @@ passt.avx2: $(PASST_SRCS) $(PASST_HEADERS) seccomp.h
> pasta.avx2 pasta.1 pasta: pasta%: passt%
> ln -sf $< $@
>
> -qrap: BASE_CPPFLAGS += -DARCH=\"$(TARGET_ARCH)\"
> -qrap: $(QRAP_SRCS) $(QRAP_HEADERS)
> -
> passt-repair: $(PASST_REPAIR_SRCS) $(PASST_REPAIR_HEADERS) seccomp_repair.h
>
> pesto: BASE_CPPFLAGS += -DPESTO
> diff --git a/README.md b/README.md
> index 8fdc0a3..43caf49 100644
> --- a/README.md
> +++ b/README.md
> @@ -376,10 +376,6 @@ speeding up local connections, and usually requiring NAT. _pasta_:
> _passt_ exchanges packets with _qemu_ via UNIX domain socket, using the `socket`
> back-end in qemu. This is supported since qemu 7.2.
>
> -For older versions, the [qrap](/passt/tree/qrap.c) wrapper can be used to
> -connect to a UNIX domain socket and to start qemu, which can now use the file
> -descriptor that's already opened.
> -
> This approach, compared to using a _tap_ device, doesn't require any security
> capabilities, as we don't need to create any interface.
>
> diff --git a/contrib/fedora/passt.spec b/contrib/fedora/passt.spec
> index 34838af..6c7530a 100644
> --- a/contrib/fedora/passt.spec
> +++ b/contrib/fedora/passt.spec
> @@ -118,12 +118,10 @@ fi
> %doc %{_docdir}/%{name}/demo.sh
> %{_bindir}/passt
> %{_bindir}/pasta
> -%{_bindir}/qrap
> %{_bindir}/passt-repair
> %{_bindir}/pesto
> %{_mandir}/man1/passt.1*
> %{_mandir}/man1/pasta.1*
> -%{_mandir}/man1/qrap.1*
> %{_mandir}/man1/passt-repair.1*
> %{_mandir}/man1/pesto.1*
> %ifarch x86_64
> diff --git a/doc/demo.sh b/doc/demo.sh
> index 6b0917c..b56669f 100755
> --- a/doc/demo.sh
> +++ b/doc/demo.sh
> @@ -177,7 +177,7 @@ into_ns() {
> next
> [ "${KEY}" = "s" ] && ${SHELL}
>
> - cmd passt -P "${DEMO_DIR}/passt.pid"
> + cmd passt -P "${DEMO_DIR}/passt.pid" -s "${DEMO_DIR}/passt.socket"
> echo
> echo "...passt is running."
> next
> @@ -198,15 +198,12 @@ into_ns() {
> echo "can download and use mbuto (https://mbuto.sh/) to build a"
> echo "basic initramfs image. Otherwise, press 's' to skip this"
> echo "step, and start an existing virtual machine yourself."
> - echo "You'll need to use the qrap(1) wrapper, with qemu options"
> - echo "as reported above."
>
> next
> else
> echo "This script doesn't know, yet, how to run a virtual"
> echo "machine on your architecture (${__arch}). Please start an"
> - echo "existing virtual machine yourself, using the qrap(1)"
> - echo "wrapper, with qemu options as reported above."
> + echo "existing virtual machine yourself."
> echo
> fi
>
> @@ -225,12 +222,13 @@ into_ns() {
> next
>
> # shellcheck disable=SC2086
> - cmd qrap 5 ${__qemu_arch} \
> + cmd ${__qemu_arch} \
> -smp "$(nproc)" -m 1024 \
> -nographic -serial stdio -nodefaults -no-reboot -vga none \
> -initrd "${DEMO_DIR}/demo.img" \
> -kernel "/boot/vmlinuz-$(uname -r)" -append "console=ttyS0" \
> - -net socket,fd=5 -net nic,model=virtio || :
> + -device virtio-net-pci,netdev=s \
> + -netdev stream,id=s,server=off,addr.type=unix,addr.path="${DEMO_DIR}/passt.socket" || :
> }
>
> STTY_BACKUP="$(stty -g)"
> diff --git a/doc/passt_overview.excalidraw b/doc/passt_overview.excalidraw
> index 790728e..3217b3f 100644
> --- a/doc/passt_overview.excalidraw
> +++ b/doc/passt_overview.excalidraw
> @@ -3595,35 +3595,6 @@
> "baseline": 17,
> "textAlign": "left",
> "verticalAlign": "top"
> - },
> - {
> - "type": "text",
> - "version": 1448,
> - "versionNonce": 1345391945,
> - "isDeleted": false,
> - "id": "c-esZiuHSm3wnTRlmIJZk",
> - "fillStyle": "hachure",
> - "strokeWidth": 1,
> - "strokeStyle": "dotted",
> - "roughness": 1,
> - "opacity": 100,
> - "angle": 4.969352159599495,
> - "x": 816.7081559166961,
> - "y": 215.74807066759342,
> - "strokeColor": "#2b8a3e",
> - "backgroundColor": "transparent",
> - "width": 211,
> - "height": 23,
> - "seed": 939668423,
> - "groupIds": [],
> - "strokeSharpness": "round",
> - "boundElementIds": [],
> - "fontSize": 20,
> - "fontFamily": 1,
> - "text": "(currently \"qrap\" wrapper)",
> - "baseline": 17,
> - "textAlign": "left",
> - "verticalAlign": "top"
> }
> ],
> "appState": {
> diff --git a/hooks/pre-push b/hooks/pre-push
> index 3e2d15f..8eebdbc 100755
> --- a/hooks/pre-push
> +++ b/hooks/pre-push
> @@ -54,7 +54,7 @@ done
> cd ..
>
> make pkgs
> -scp passt passt.avx2 passt.1 qrap qrap.1 "${USER_HOST}:${BIN}"
> +scp passt passt.avx2 passt.1 "${USER_HOST}:${BIN}"
> scp pasta pasta.avx2 pasta.1 "${USER_HOST}:${BIN}"
> scp passt-repair passt-repair.1 "${USER_HOST}:${BIN}"
> scp pesto pesto.1 "${USER_HOST}:${BIN}"
> diff --git a/passt.1 b/passt.1
> index 995590a..53e072a 100644
> --- a/passt.1
> +++ b/passt.1
> @@ -580,8 +580,7 @@ Default is \fBnone\fR for \fBpasst\fR and \fBauto\fR for \fBpasta\fR.
>
> .TP
> .BR \-s ", " \-\-socket-path ", " \-\-socket " " \fIpath
> -Path for UNIX domain socket used by \fBqemu\fR(1) or \fBqrap\fR(1) to connect to
> -\fBpasst\fR.
> +Path for UNIX domain socket used by \fBqemu\fR(1) to connect to \fBpasst\fR.
> Default is to probe a free socket, not accepting connections, starting from
> \fI/tmp/passt_1.socket\fR to \fI/tmp/passt_64.socket\fR.
>
> @@ -762,129 +761,132 @@ forwards loopback traffic between namespaces.
> .RS
> .nf
> $ iperf3 -s -D
> -$ ./pasta
> -Outbound interface: eth0, namespace interface: eth0
> -ARP:
> - address: 28:16:ad:39:a9:ea
> -DHCP:
> - assign: 192.168.1.118
> - mask: 255.255.255.0
> - router: 192.168.1.1
> -NDP/DHCPv6:
> - assign: 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17
> - router: fe80::62e3:27ff:fe33:2b01
> -#
> -# dhclient -4 --no-pid
> -# dhclient -6 --no-pid
> +
> +$ pasta --config-net
> +
> # ip address show
> 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
> link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
> inet 127.0.0.1/8 scope host lo
> valid_lft forever preferred_lft forever
> - inet6 ::1/128 scope host
> + inet6 ::1/128 scope host proto kernel_lo
> valid_lft forever preferred_lft forever
> -2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc pfifo_fast state UNKNOWN group default qlen 1000
> - link/ether 5e:90:02:eb:b0:2a brd ff:ff:ff:ff:ff:ff
> - inet 192.168.1.118/24 brd 192.168.1.255 scope global eth0
> +2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
> + link/ether be:16:49:5a:65:dc brd ff:ff:ff:ff:ff:ff
> + inet 88.198.0.164/27 brd 88.198.0.191 scope global noprefixroute enp9s0
> valid_lft forever preferred_lft forever
> - inet6 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17/128 scope global
> + inet6 2a01:4f8:222:904::2/64 scope global nodad
> valid_lft forever preferred_lft forever
> - inet6 2a02:6d40:3ca5:2001:5c90:2ff:feeb:b02a/64 scope global dynamic mngtmpaddr
> - valid_lft 3591sec preferred_lft 3591sec
> - inet6 fe80::5c90:2ff:feeb:b02a/64 scope link
> + inet6 fe80::bc16:49ff:fe5a:65dc/64 scope link nodad proto kernel_ll
> valid_lft forever preferred_lft forever
> +
> # ip route show
> -default via 192.168.1.1 dev eth0
> -192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.118
> +default via 88.198.0.161 dev enp9s0 proto dhcp metric 1002
> +88.198.0.160/27 dev enp9s0 proto dhcp scope link metric 1002
> +
> # ip -6 route show
> -2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17 dev eth0 proto kernel metric 256 pref medium
> -2a02:6d40:3ca5:2001::/64 dev eth0 proto kernel metric 256 expires 3584sec pref medium
> -fe80::/64 dev eth0 proto kernel metric 256 pref medium
> -default via fe80::62e3:27ff:fe33:2b01 dev eth0 proto ra metric 1024 expires 3584sec pref medium
> +2a01:4f8:222:904::/64 dev enp9s0 proto kernel metric 256 pref medium
> +fe80::/64 dev enp9s0 proto kernel metric 256 pref medium
> +default via fe80::1 dev enp9s0 metric 1024 onlink pref medium
> +
> # iperf3 -c 127.0.0.1 -t1
> Connecting to host 127.0.0.1, port 5201
> -[ 5] local 127.0.0.1 port 51938 connected to 127.0.0.1 port 5201
> +[ 5] local 127.0.0.1 port 59112 connected to 127.0.0.1 port 5201
> [ ID] Interval Transfer Bitrate Retr Cwnd
> -[ 5] 0.00-1.00 sec 4.46 GBytes 38.3 Gbits/sec 0 3.93 MBytes
> +[ 5] 0.00-1.00 sec 3.89 GBytes 33.4 Gbits/sec 0 2.62 MBytes
> - - - - - - - - - - - - - - - - - - - - - - - - -
> [ ID] Interval Transfer Bitrate Retr
> -[ 5] 0.00-1.00 sec 4.46 GBytes 38.3 Gbits/sec 0 sender
> -[ 5] 0.00-1.41 sec 4.45 GBytes 27.1 Gbits/sec receiver
> +[ 5] 0.00-1.00 sec 3.89 GBytes 33.4 Gbits/sec 0 sender
> +[ 5] 0.00-1.00 sec 3.89 GBytes 33.4 Gbits/sec receiver
>
> iperf Done.
> +
> # iperf3 -c ::1 -t1
> Connecting to host ::1, port 5201
> -[ 5] local ::1 port 50108 connected to ::1 port 5201
> +[ 5] local ::1 port 49138 connected to ::1 port 5201
> [ ID] Interval Transfer Bitrate Retr Cwnd
> -[ 5] 0.00-1.00 sec 4.35 GBytes 37.4 Gbits/sec 0 4.99 MBytes
> +[ 5] 0.00-1.00 sec 4.32 GBytes 37.0 Gbits/sec 0 1.06 MBytes
> - - - - - - - - - - - - - - - - - - - - - - - - -
> [ ID] Interval Transfer Bitrate Retr
> -[ 5] 0.00-1.00 sec 4.35 GBytes 37.4 Gbits/sec 0 sender
> -[ 5] 0.00-1.41 sec 4.35 GBytes 26.4 Gbits/sec receiver
> +[ 5] 0.00-1.00 sec 4.32 GBytes 37.0 Gbits/sec 0 sender
> +[ 5] 0.00-1.00 sec 4.32 GBytes 37.0 Gbits/sec receiver
>
> iperf Done.
> -# ping -c1 -4 spaghetti.pizza
> -PING spaghetti.pizza (172.67.192.217) 56(84) bytes of data.
> -64 bytes from 172.67.192.217: icmp_seq=1 ttl=255 time=37.3 ms
> +
> +# ping -nc1 -4 spaghetti.pizza
> +PING spaghetti.pizza (5.161.47.86) 56(84) bytes of data.
> +64 bytes from 5.161.47.86: icmp_seq=1 ttl=255 time=99.4 ms
>
> --- spaghetti.pizza ping statistics ---
> 1 packets transmitted, 1 received, 0% packet loss, time 0ms
> -# ping -c1 -6 spaghetti.pizza
> -PING spaghetti.pizza(2606:4700:3034::6815:147a (2606:4700:3034::6815:147a)) 56 data bytes
> -64 bytes from 2606:4700:3034::6815:147a: icmp_seq=1 ttl=255 time=35.6 ms
> +rtt min/avg/max/mdev = 99.433/99.433/99.433/0.000 ms
> +# ping -nc1 -6 spaghetti.pizza
> +PING spaghetti.pizza (2a01:4f8:1c1e:d6f1::1) 56 data bytes
> +64 bytes from 2a01:4f8:1c1e:d6f1::1: icmp_seq=1 ttl=255 time=3.11 ms
>
> --- spaghetti.pizza ping statistics ---
> 1 packets transmitted, 1 received, 0% packet loss, time 0ms
> -rtt min/avg/max/mdev = 35.605/35.605/35.605/0.000 ms
> -# logout
> -$
> -
> -.RE
> +rtt min/avg/max/mdev = 3.110/3.110/3.110/0.000 ms
> .fi
> +.RE
>
> .BR "Connect an existing user and network namespace"
> .RS
> .nf
> $ unshare -rUn
> -# echo $$
> -2446678
>
> +# echo $$
> +1295969
> .fi
> -.BR " [From another terminal]"
> +
> +.BR "[From another terminal]"
> .nf
> -$ ./pasta 2446678
> -Outbound interface: eth0, namespace interface: eth0
> -ARP:
> - address: 28:16:ad:39:a9:ea
> +$ pasta --config-net 1295969
> +Template interface: enp9s0 (IPv4), enp9s0 (IPv6)
> +Namespace interface: enp9s0
> +MAC:
> + host: 9a:55:9a:55:9a:55
> + NAT to host 127.0.0.1: 88.198.0.161
> DHCP:
> - assign: 192.168.1.118
> - mask: 255.255.255.0
> - router: 192.168.1.1
> + assign: 88.198.0.164
> + mask: 255.255.255.224
> + router: 88.198.0.161
> +DNS:
> + 185.12.64.1
> + 185.12.64.2
> + NAT to host ::1: fe80::1
> NDP/DHCPv6:
> - assign: 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17
> - router: fe80::62e3:27ff:fe33:2b01
> -
> + assign: 2a01:4f8:222:904::2
> + router: fe80::1
> + our link-local: fe80::1
> +Inbound forwarding rules (HOST):
> + TCP [*]:1-32767 => 1-32767 (best effort) (auto-scan)
> + TCP [*]:61000-65535 => 61000-65535 (best effort) (auto-scan)
> + UDP [*]:1-32767 => 1-32767 (best effort) (auto-scan)
> + UDP [*]:61000-65535 => 61000-65535 (best effort) (auto-scan)
> +Outbound forwarding rules (SPLICE):
> + TCP [*]%lo:1-32767 => 1-32767 (best effort) (auto-scan)
> + TCP [*]%lo:61000-65535 => 61000-65535 (best effort) (auto-scan)
> + UDP [*]%lo:1-32767 => 1-32767 (best effort) (auto-scan)
> + UDP [*]%lo:61000-65535 => 61000-65535 (best effort) (auto-scan)
> .fi
> -.BR " [Back to the original terminal]"
> +
> +.BR "[Back to the original terminal]"
> .nf
> -# dhclient -4 --no-pid
> -# dhclient -6 --no-pid
> # ip address show
> 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
> link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
> inet 127.0.0.1/8 scope host lo
> valid_lft forever preferred_lft forever
> - inet6 ::1/128 scope host
> + inet6 ::1/128 scope host proto kernel_lo
> valid_lft forever preferred_lft forever
> -2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc pfifo_fast state UNKNOWN group default qlen 1000
> - link/ether fa:c1:2a:27:92:a9 brd ff:ff:ff:ff:ff:ff
> - inet 192.168.1.118/24 brd 192.168.1.255 scope global eth0
> +2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
> + link/ether 9a:44:5e:54:d3:2c brd ff:ff:ff:ff:ff:ff
> + inet 88.198.0.164/27 brd 88.198.0.191 scope global noprefixroute enp9s0
> valid_lft forever preferred_lft forever
> - inet6 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17/128 scope global
> + inet6 2a01:4f8:222:904::2/64 scope global nodad
> valid_lft forever preferred_lft forever
> - inet6 2a02:6d40:3ca5:2001:f8c1:2aff:fe27:92a9/64 scope global dynamic mngtmpaddr
> - valid_lft 3594sec preferred_lft 3594sec
> - inet6 fe80::f8c1:2aff:fe27:92a9/64 scope link
> + inet6 fe80::9844:5eff:fe54:d32c/64 scope link nodad proto kernel_ll
> valid_lft forever preferred_lft forever
> .fi
> .RE
> @@ -893,72 +895,69 @@ NDP/DHCPv6:
> .BR "Start and connect a guest with basic port forwarding"
> .RS
> .nf
> -$ ./passt -f -t 2222:22
> -Outbound interface: eth0
> -ARP:
> - address: 28:16:ad:39:a9:ea
> +$ passt -f -t 2222:22
> +UNIX domain socket bound at /tmp/passt_1.socket
> +No IPv6 nameserver available for NDP/DHCPv6
> +Template interface: enp9s0 (IPv4), enp9s0 (IPv6)
> +MAC:
> + host: 9a:55:9a:55:9a:55
> + NAT to host 127.0.0.1: 88.198.0.161
> DHCP:
> - assign: 192.168.1.118
> - mask: 255.255.255.0
> - router: 192.168.1.1
> - search:
> - redhat.com
> + assign: 88.198.0.164
> + mask: 255.255.255.224
> + router: 88.198.0.161
> +DNS:
> + 185.12.64.1
> + 185.12.64.2
> + NAT to host ::1: fe80::1
> NDP/DHCPv6:
> - assign: 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17
> - router: fe80::62e3:27ff:fe33:2b01
> - search:
> - redhat.com
> -UNIX domain socket bound at /tmp/passt_1.socket
> -
> -You can now start qrap:
> - ./qrap 5 qemu-system-x86_64 ... -net socket,fd=5 -net nic,model=virtio
> -or directly qemu, patched with:
> - qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch
> -as follows:
> - qemu-system-x86_64 ... -net socket,connect=/tmp/passt_1.socket -net nic,model=virtio
> -
> + assign: 2a01:4f8:222:904::2
> + router: fe80::1
> + our link-local: fe80::1
> +Inbound forwarding rules (HOST):
> + TCP [*]:2222 => 22
> +
> +You can now start qemu (>= 7.2, with commit 13c6be96618c):
> + kvm ... -device virtio-net-pci,netdev=s -netdev stream,id=s,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket
> .fi
> -.BR " [From another terminal]"
> -.nf
> -$ ./qrap 5 qemu-system-x86_64 test.qcow2 -m 1024 -display none -nodefaults -nographic -net socket,fd=5 -net nic,model=virtio
> -Connected to /tmp/passt_1.socket
>
> -.fi
> -.BR " [Back to the original terminal]"
> +.BR "[From another terminal]"
> .nf
> -passt: DHCP: ack to request
> -passt: from 52:54:00:12:34:56
> -passt: NDP: received NS, sending NA
> -passt: NDP: received RS, sending RA
> -passt: DHCPv6: received SOLICIT, sending ADVERTISE
> -passt: NDP: received NS, sending NA
> -passt: DHCPv6: received REQUEST/RENEW/CONFIRM, sending REPLY
> -passt: NDP: received NS, sending NA
> +$ qemu-system-x86_64 -m 128 test.qcow2 -display none -nodefaults -nographic -device virtio-net-pci,netdev=s -netdev stream,id=s,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket
> +.fi
>
> +.BR "[Back to the original terminal]"
> +.nf
> +accepted connection from PID 1301736
> +New guest MAC address observed: 52:54:00:12:34:56
> +DHCP: offer to discover
> + from 52:54:00:12:34:56
> +DHCP: ack to request
> + from 52:54:00:12:34:56
> +NDP: received RS, sending RA
> .fi
> -.BR " [From yet another terminal]"
> +
> +.BR "[From yet another terminal]"
> .nf
> $ ssh -p 2222 root@localhost
> root@localhost's password:
> .fi
> -.BR " [...]"
> +.BR "[...]"
> .nf
> # ip address show
> -1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
> +1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
> link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
> inet 127.0.0.1/8 scope host lo
> valid_lft forever preferred_lft forever
> inet6 ::1/128 scope host
> valid_lft forever preferred_lft forever
> -2: ens2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc pfifo_fast state UP group default qlen 1000
> +2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
> link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
> - inet 192.168.1.118/24 brd 192.168.1.255 scope global noprefixroute ens2
> + inet 88.198.0.164/27 scope global eth0
> valid_lft forever preferred_lft forever
> - inet6 2a02:6d40:3ca5:2001:b81d:fa4a:8cdd:cf17/128 scope global noprefixroute
> + inet6 2a01:4f8:222:904:5054:ff:fe12:3456/64 scope global dynamic flags 100
> valid_lft forever preferred_lft forever
> - inet6 2a02:6d40:3ca5:2001:b019:9ae2:a2fe:e6b4/64 scope global dynamic noprefixroute
> - valid_lft 3588sec preferred_lft 3588sec
> - inet6 fe80::1f98:d09f:9309:9e77/64 scope link noprefixroute
> + inet6 fe80::5054:ff:fe12:3456/64 scope link
> valid_lft forever preferred_lft forever
> .fi
> .RE
> diff --git a/qrap.1 b/qrap.1
> deleted file mode 100644
> index 98cc877..0000000
> --- a/qrap.1
> +++ /dev/null
> @@ -1,77 +0,0 @@
> -.\" SPDX-License-Identifier: GPL-2.0-or-later
> -.\" Copyright (c) 2020-2021 Red Hat GmbH
> -.\" Author: Stefano Brivio <sbrivio@redhat.com>
> -.TH qrap 1
> -
> -.SH NAME
> -.B qrap
> -\- temporary qemu wrapper connecting UNIX domain socket to file descriptor
> -
> -.SH SYNOPSIS
> -.B qrap
> -[\fIFDNUM\fR \fIQEMU_CMD\fR] [\fIQEMU_ARG\fR]...
> -.SH DESCRIPTION
> -\fBqrap\fR is a wrapper, designed specifically for usage with \fBqemu\fR(1) and
> -\fBpasst\fR(1), connecting a UNIX domain socket to a file descriptor, and
> -running \fBqemu\fR(1) with given arguments.
> -
> -A running instance of \fBpasst\fR(1) is probed checking for UNIX domain sockets,
> -answering a dummy ARP request, with names starting from
> -\fI/tmp/passt_1.socket\fR up to \fI/tmp/passt_64.socket\fR.
> -
> -If first and second arguments are not a socket number and a command, that is,
> -respectively, \fIFDNUM\fR and \fIQEMU_CMD\fR, \fBqrap\fR will try to locate a
> -qemu executable in \fBPATH\fR and patch the command line to specify a network
> -device and a \fInetdev\fR back-end for usage with \fBpasst\fR(1).
> -
> -If \fBqrap\fR patches the command line, it will remove any potentially
> -conflicting network device, that is, any \fI-netdev\fR or \fI-net\fR option, or
> -any \fI-device\fR option with argument starting with \fIvirtio-net-pci,\fR,
> -\fIvirtio-net-ccw,\fR, \fIe1000,\fR, \fIe1000e,\fR, or \fIrtl8139,\fR.
> -
> -.SH EXAMPLES
> -
> -.BR "Start qemu explicitly passing its command name and a socket number"
> -.RS
> -.nf
> -$ ./qrap 5 kvm test.qcow2 -m 1024 -display none -nodefaults -nographic -net socket,fd=5 -net nic,model=virtio
> -.fi
> -.RE
> -
> -.BR "Start qemu without command name and socket number, patching arguments"
> -.RS
> -.nf
> -$ ./qrap test.qcow2 -m 1024 -display none -nodefaults -nographic
> -.fi
> -.RE
> -
> -.SH NOTES
> -
> -This wrapper is temporary: qemu commit 13c6be96618c ("net: stream: add unix
> -socket") introduces native AF_UNIX socket support, and it should be included in
> -qemu starting from the 7.2 release. It will be around for a little bit longer to
> -give users enough time to switch.
> -
> -.SH AUTHOR
> -
> -Stefano Brivio <sbrivio@redhat.com>
> -
> -.SH REPORTING BUGS
> -
> -No public bug tracker is available at this time. For the moment being, report
> -issues to Stefano Brivio <sbrivio@redhat.com>.
> -
> -.SH COPYRIGHT
> -
> -Copyright (c) 2020-2021 Red Hat GmbH.
> -
> -\fBqrap\fR is free software: you can redistribute is and/or modify it under the
> -terms of the GNU General Public License as published by the Free Software
> -Foundation, either version 2 of the License, or (at your option) any later
> -version.
> -
> -.SH SEE ALSO
> -
> -\fBqemu\fR(1), \fBpasst\fR(1).
> -
> -High-level documentation is available at https://passt.top/passt/about/.
> diff --git a/qrap.c b/qrap.c
> deleted file mode 100644
> index d596706..0000000
> --- a/qrap.c
> +++ /dev/null
> @@ -1,429 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -
> -/* PASST - Plug A Simple Socket Transport
> - *
> - * qrap.c - qemu wrapper connecting UNIX domain socket to file descriptor
> - *
> - * Copyright (c) 2020-2021 Red Hat GmbH
> - * Author: Stefano Brivio <sbrivio@redhat.com>
> - *
> - * TODO: Drop this implementation once qemu commit 13c6be96618c ("net: stream:
> - * add unix socket") is included in a release (7.2), and once we can reasonably
> - * assume existing users switched to it.
> - */
> -
> -#include <stdio.h>
> -#include <stdint.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <unistd.h>
> -#include <sys/types.h>
> -#include <sys/socket.h>
> -#include <errno.h>
> -#include <linux/limits.h>
> -#include <limits.h>
> -#include <fcntl.h>
> -#include <net/if_arp.h>
> -#include <netinet/in.h>
> -#include <netinet/ip6.h>
> -#include <netinet/if_ether.h>
> -#include <time.h>
> -
> -#include <linux/icmpv6.h>
> -
> -#include "util.h"
> -#include "ip.h"
> -#include "passt.h"
> -#include "arp.h"
> -
> -static char *qemu_names[] = {
> - "kvm",
> - "qemu-kvm",
> -#ifdef ARCH
> - ( "qemu-system-" ARCH ),
> -#endif
> - "/usr/libexec/qemu-kvm",
> - NULL,
> -};
> -
> -/**
> - * struct drop_arg - Drop matching arguments on command line
> - * @name: Option name
> - * @val: Substring in option value, NULL matches any value
> - */
> -static const struct drop_arg {
> - char *name;
> - char *val;
> -} drop_args[] = {
> - { "-netdev", NULL },
> - { "-net", NULL },
> - { "-device", "virtio-net-pci," },
> - { "-device", "{\"driver\":\"virtio-net-pci\"," },
> - { "-device", "virtio-net-ccw," },
> - { "-device", "{\"driver\":\"virtio-net-ccw\"," },
> - { "-device", "e1000," },
> - { "-device", "{\"driver\":\"e1000\"," },
> - { "-device", "e1000e," },
> - { "-device", "{\"driver\":\"e1000e\"," },
> - { "-device", "rtl8139," },
> - { "-device", "{\"driver\":\"rtl8139\"," },
> - { 0 },
> -};
> -
> -/**
> - * struct pci_dev - PCI devices to add on command line depending on machine name
> - * @mach: Machine name
> - * @name: Device ("-device") name to insert
> - * @template: Prefix for device specification (first part of address)
> - * @template_post: Suffix for device specification (last part of address)
> - * @template_json: Device prefix for when JSON is used
> - * @template_json_post: Device suffix for when JSON is used
> - * @base: Base used for PCI addresses
> - * @first: First usable PCI address
> - * @last: Last usable PCI address
> - */
> -static const struct pci_dev {
> - char *mach;
> - char *name;
> - char *template;
> - char *template_post;
> - char *template_json;
> - char *template_json_post;
> - int base;
> - int first;
> - int last;
> -} pci_devs[] = {
> - {
> - "pc-q35", "virtio-net-pci",
> - "bus=pci.", ",addr=0x0",
> - "\"bus\":\"pci.", ",\"addr\":\"0x0\"",
> - 10, 3, /* 2: hotplug bus */ 31
> - },
> - {
> - "pc-", "virtio-net-pci",
> - "bus=pci.0,addr=0x", "",
> - "\"bus\":\"pci.0\",\"addr\":\"0x", "",
> - 16, 2, /* 1: ISA bridge */ 31
> - },
> - {
> - "s390-ccw", "virtio-net-ccw",
> - "devno=fe.0.", "",
> - "\"devno\":\"fe.0.", "",
> - 16, 1, 16
> - },
> - { 0 },
> -};
> -
> -#define DEFAULT_FD 5
> -
> -/**
> - * usage() - Print usage and exit
> - * @name: Executable name
> - */
> -void usage(const char *name)
> -{
> - fprintf(stderr, "Usage: %s [FDNUM QEMU_CMD] [QEMU_ARG]...\n", name);
> - fprintf(stderr, "\n");
> - fprintf(stderr, "If first and second arguments aren't a socket number\n"
> - "and a path, %s will try to locate a qemu binary\n"
> - "and directly patch the command line\n", name);
> -
> - exit(EXIT_FAILURE);
> -}
> -
> -/**
> - * main() - Entry point and main loop
> - * @argc: Argument count
> - * @argv: File descriptor number, then qemu with arguments
> - *
> - * Return: 0 once interrupted, non-zero on failure
> - */
> -int main(int argc, char **argv)
> -{
> - int i, s, qemu_argc = 0, addr_map = 0, has_dev = 0, has_json = 0, retry_on_reset, rc;
> - struct timeval tv = { .tv_sec = 0, .tv_usec = (long)(500 * 1000) };
> - char *qemu_argv[ARG_MAX], dev_str[ARG_MAX];
> - struct sockaddr_un addr = {
> - .sun_family = AF_UNIX,
> - };
> - const struct pci_dev *dev = NULL;
> - long fd;
> - struct {
> - uint32_t vnet_len4;
> - struct ethhdr eh4;
> - struct arphdr ah;
> - struct arpmsg am;
> -
> - uint32_t vnet_len6;
> - struct ethhdr eh6;
> - struct ipv6hdr ip6hr;
> - struct icmp6hdr ihr;
> - struct in6_addr target;
> - } __attribute__((__packed__)) probe = {
> - .vnet_len4 = htonl(42),
> - {
> - .h_dest = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
> - .h_source = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
> - .h_proto = htons(ETH_P_ARP),
> - },
> - { .ar_hrd = htons(ARPHRD_ETHER),
> - .ar_pro = htons(ETH_P_IP),
> - .ar_hln = ETH_ALEN,
> - .ar_pln = 4,
> - .ar_op = htons(ARPOP_REQUEST),
> - },
> - {
> - .sha = { 0 }, .sip = { 0 }, .tha = { 0 }, .tip = { 0 },
> - },
> - .vnet_len6 = htonl(78),
> - {
> - .h_dest = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
> - .h_source = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
> - .h_proto = htons(ETH_P_IPV6),
> - },
> - {
> - .version = 6,
> - .payload_len = htons(24),
> - .nexthdr = IPPROTO_ICMPV6,
> - .hop_limit = 255,
> - .saddr = IN6ADDR_LOOPBACK_INIT,
> - .daddr = IN6ADDR_ANY_INIT,
> - },
> - {
> - .icmp6_type = 135,
> - .icmp6_code = 0,
> - },
> - IN6ADDR_ANY_INIT,
> - };
> - char probe_r;
> -
> - if (argc >= 3) {
> - const char *path = getenv("PATH");
> - errno = 0;
> - fd = strtol(argv[1], NULL, 0);
> - if (fd >= 3 && fd < INT_MAX && !errno && path) {
> - char env_path[ARG_MAX + 1], *p, command[ARG_MAX];
> -
> - strncpy(env_path, path, ARG_MAX);
> - /* cppcheck-suppress strtokCalled */
> - p = strtok(env_path, ":");
> - while (p) {
> - snprintf(command, ARG_MAX, "%s/%s", p, argv[2]);
> - if (!access(command, X_OK))
> - goto valid_args;
> -
> - /* cppcheck-suppress strtokCalled */
> - p = strtok(NULL, ":");
> - }
> - }
> - }
> -
> - fd = DEFAULT_FD;
> -
> - for (i = 1; i < argc - 1; i++) {
> - if (strcmp(argv[i], "-machine"))
> - continue;
> -
> - for (dev = pci_devs; dev->mach; dev++) {
> - if (strstr(argv[i + 1], dev->mach) == argv[i + 1])
> - break;
> - }
> - }
> -
> - if (!dev || !dev->mach)
> - dev = pci_devs;
> -
> - for (qemu_argc = 1, i = 1; i < argc; i++) {
> - const struct drop_arg *a;
> -
> - for (a = drop_args; a->name; a++) {
> - if (!strcmp(argv[i], a->name)) {
> - if (!a->val)
> - break;
> -
> - if (i + 1 < argc &&
> - strstr(argv[i + 1], a->val) == argv[i + 1])
> - break;
> - }
> - }
> - if (a->name) {
> - i++;
> - continue;
> - }
> -
> - if (!strcmp(argv[i], "-device") && i + 1 < argc) {
> - const char *template = NULL;
> - const char *p;
> -
> - has_dev = 1;
> -
> - if ((p = strstr(argv[i + 1], dev->template))) {
> - template = dev->template;
> - } else if ((p = strstr(argv[i + 1], dev->template_json))) {
> - template = dev->template_json;
> - has_json = 1;
> - }
> -
> - if (template) {
> - long n;
> -
> - n = strtol(p + strlen(template), NULL, dev->base);
> - if (!errno)
> - addr_map |= (1 << n);
> - }
> - }
> -
> - qemu_argv[qemu_argc++] = argv[i];
> - }
> -
> - for (i = dev->first; i < dev->last; i++) {
> - if (!(addr_map & (1 << i)))
> - break;
> - }
> - if (i == dev->last) {
> - fprintf(stderr, "Couldn't find free address for device\n");
> - usage(argv[0]);
> - }
> -
> - if (has_dev) {
> - qemu_argv[qemu_argc++] = "-device";
> - if (!has_json) {
> - if (dev->base == 16) {
> - snprintf(dev_str, ARG_MAX,
> - "%s,%s%x%s,netdev=hostnet0,x-txburst=4096",
> - dev->name, dev->template, i, dev->template_post);
> - } else if (dev->base == 10) {
> - snprintf(dev_str, ARG_MAX,
> - "%s,%s%d%s,netdev=hostnet0,x-txburst=4096",
> - dev->name, dev->template, i, dev->template_post);
> - }
> - } else {
> - if (dev->base == 16) {
> - snprintf(dev_str, ARG_MAX,
> - "{\"driver\":\"%s\",%s%x\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}",
> - dev->name, dev->template_json, i, dev->template_json_post);
> - } else if (dev->base == 10) {
> - snprintf(dev_str, ARG_MAX,
> - "{\"driver\":\"%s\",%s%d\"%s,\"netdev\":\"hostnet0\",\"x-txburst\":4096}",
> - dev->name, dev->template_json, i, dev->template_json_post);
> - }
> - }
> - qemu_argv[qemu_argc++] = dev_str;
> - }
> -
> - qemu_argv[qemu_argc++] = "-netdev";
> - if (!has_json) {
> - qemu_argv[qemu_argc++] = "socket,fd=" STR(DEFAULT_FD) ",id=hostnet0";
> - } else {
> - qemu_argv[qemu_argc++] = "{\"type\":\"socket\",\"fd\":\"" STR(DEFAULT_FD) "\",\"id\":\"hostnet0\"}";
> - }
> - qemu_argv[qemu_argc] = NULL;
> -
> -valid_args:
> - for (i = 1; i < UNIX_SOCK_MAX; i++) {
> - retry_on_reset = 50;
> -
> -retry:
> - s = socket(AF_UNIX, SOCK_STREAM, 0);
> - if (s < 0) {
> - perror("socket");
> - exit(EXIT_FAILURE);
> - }
> -
> - if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
> - perror("setsockopt SO_RCVTIMEO");
> - if (setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)))
> - perror("setsockopt SO_SNDTIMEO");
> -
> - snprintf(addr.sun_path, UNIX_PATH_MAX, UNIX_SOCK_PATH, i);
> -
> - errno = 0;
> -
> - if (connect(s, (const struct sockaddr *)&addr, sizeof(addr))) {
> - rc = errno;
> - perror("connect");
> - } else if (send(s, &probe, sizeof(probe), 0) != sizeof(probe)) {
> - rc = errno;
> - perror("send");
> - } else if (recv(s, &probe_r, 1, MSG_PEEK) <= 0) {
> - rc = errno;
> - perror("recv");
> - } else {
> - break;
> - }
> -
> - /* FIXME: in a KubeVirt environment, libvirtd invokes qrap three
> - * times in a strict sequence when a virtual machine needs to
> - * be started, namely, when:
> - * - the domain XML is saved
> - * - the domain is started (for "probing")
> - * - the virtual machine is started for real
> - * and it often happens that the qemu process is still running
> - * when qrap is invoked again, so passt will refuse the new
> - * connection because the previous one is still active. This
> - * overlap seems to be anywhere between 0 and 3ms.
> - *
> - * If we get a connection reset, retry a few times, to allow for
> - * the previous qemu instance to terminate and, in turn, for the
> - * connection to passt to be closed.
> - *
> - * This should be fixed in libvirt instead. It probably makes
> - * sense to check this behaviour once native libvirt support is
> - * there, and this implies native qemu support too, so at that
> - * point qrap will have no reason to exist anymore -- that is,
> - * this FIXME will probably remain until the tool itself is
> - * obsoleted.
> - */
> - if (retry_on_reset && rc == ECONNRESET) {
> - retry_on_reset--;
> - /* cppcheck-suppress usleepCalled */
> - usleep(50 * 1000);
> - goto retry;
> - }
> -
> - fprintf(stderr, "Probe of %s failed\n", addr.sun_path);
> -
> - close(s);
> - }
> -
> - if (i == UNIX_SOCK_MAX) {
> - perror("connect");
> - exit(EXIT_FAILURE);
> - }
> -
> - tv.tv_usec = 0;
> - if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
> - perror("setsockopt, SO_RCVTIMEO reset");
> - if (setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)))
> - perror("setsockopt, SO_SNDTIMEO reset");
> -
> - fprintf(stderr, "Connected to %s\n", addr.sun_path);
> -
> - if (dup2(s, (int)fd) < 0) {
> - perror("dup");
> - exit(EXIT_FAILURE);
> - }
> -
> - close(s);
> -
> - if (qemu_argc) {
> - char **name;
> -
> - for (name = qemu_names; *name; name++) {
> - qemu_argv[0] = *name;
> - execvp(*name, qemu_argv);
> - if (errno != ENOENT) {
> - perror("execvp");
> - usage(argv[0]);
> - }
> - }
> - if (errno == ENOENT)
> - fprintf(stderr, "Couldn't find qemu command\n");
> - } else {
> - execvp(argv[2], argv + 2);
> - }
> -
> - perror("execvp");
> -
> - return EXIT_FAILURE;
> -}
> diff --git a/tap.c b/tap.c
> index cf87591..dfa66c7 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -1377,8 +1377,6 @@ static void tap_backend_show_hints(const struct ctx *c)
> info("\nYou can now start qemu (>= 7.2, with commit 13c6be96618c):");
> info(" kvm ... -device virtio-net-pci,netdev=s -netdev stream,id=s,server=off,addr.type=unix,addr.path=%s",
> c->sock_path);
> - info("or qrap, for earlier qemu versions:");
> - info(" ./qrap 5 kvm ... -net socket,fd=5 -net nic,model=virtio");
> break;
> case MODE_VU:
> info("You can start qemu with:");
> diff --git a/test/distro/opensuse b/test/distro/opensuse
> index eab722b..9ceb0bd 100644
> --- a/test/distro/opensuse
> +++ b/test/distro/opensuse
> @@ -39,7 +39,7 @@ hostb ./passt -s __STATEDIR__/passt.socket -P __PIDFILE__ &
> sleep 1
> host echo
> hout DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | head -1
> -hout GUEST_FILES ls -1 *.c *.h *.sh passt.1 qrap.1 Makefile README.md | tr '\n' ' '; echo
> +hout GUEST_FILES ls -1 *.c *.h *.sh passt.1 Makefile README.md | tr '\n' ' '; echo
>
>
> test OpenSUSE Leap 15.1
> --
> 2.43.0
>
--
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 --]
prev parent reply other threads:[~2026-07-19 4:21 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-18 7:42 Stefano Brivio
2026-07-19 4:03 ` David Gibson [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alxMmhYZ3Q0bArNU@gractus.seuss \
--to=david@gibson.dropbear.id.au \
--cc=abologna@redhat.com \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).